From c413fa10260e1964aedec291e7e1e883760f4910 Mon Sep 17 00:00:00 2001 From: nevermore Date: Sat, 29 Mar 2025 14:42:42 +0800 Subject: [PATCH 01/15] Update release.yml fix nuget path on windows --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52df96d..8b6dead 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,7 @@ jobs: - name: Publish WPF NuGet package run: | if (Test-Path "./nugets/*.nupkg") { - dotnet nuget push "./nugets/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + dotnet nuget push ".\nugets\*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate } - name: Upload WPF NuGet Artifact From 5c4fc4d4edbda5e15f6d71072c18028510866b51 Mon Sep 17 00:00:00 2001 From: Easley Date: Sat, 29 Mar 2025 17:26:05 +0800 Subject: [PATCH 02/15] uncomplete --- .../ContentRegion.cs | 25 ++++++++-- .../ItemsRegion.cs | 12 +++-- .../NavigationExtension.cs | 26 +++++++--- .../{AvaloniauiRegion.cs => Region.cs} | 5 +- .../RegionsExtension.cs | 2 +- .../TabRegion.cs | 50 +++++++++++++++---- .../Views/ViewAlpha.axaml | 7 +++ .../ContentRegion.cs | 23 ++++++++- src/Lemon.ModuleNavigation.Wpf/ItemsRegion.cs | 10 ++-- .../NavigationExtension.cs | 16 +++--- src/Lemon.ModuleNavigation.Wpf/Region.cs | 1 + src/Lemon.ModuleNavigation.Wpf/TabRegion.cs | 11 +++- .../MainWindow.xaml | 1 + .../Abstractions/IRegion.cs | 3 ++ .../Abstractions/IRegionManager.cs | 2 + .../Abstractions/IViewNavigationHandler.cs | 2 + .../Abstractions/IViewNavigationService.cs | 6 ++- .../Core/RegionNameNotFoundException.cs | 9 ++++ .../NavigationContext.cs | 2 +- .../NavigationHandler.cs | 5 ++ .../NavigationService.cs | 21 +++++--- src/Lemon.ModuleNavigation/RegionManager.cs | 24 +++++++++ 22 files changed, 214 insertions(+), 49 deletions(-) rename src/Lemon.ModuleNavigation.Avaloniaui/{AvaloniauiRegion.cs => Region.cs} (95%) create mode 100644 src/Lemon.ModuleNavigation/Core/RegionNameNotFoundException.cs diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/ContentRegion.cs b/src/Lemon.ModuleNavigation.Avaloniaui/ContentRegion.cs index c2973b3..5b9e49b 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/ContentRegion.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/ContentRegion.cs @@ -4,7 +4,7 @@ namespace Lemon.ModuleNavigation.Avaloniaui; -public class ContentRegion : AvaloniauiRegion +public class ContentRegion : Region { private readonly ContentControl _contentControl; public ContentRegion(ContentControl contentControl, string name) : base() @@ -44,11 +44,30 @@ public override void Activate(NavigationContext target) } } Content = target; + Contexts.Add(target); } - public override void DeActivate(NavigationContext target) + public override void DeActivate(string regionName) { - Content = null; + if (Content is NavigationContext current) + { + if (current.TargetViewName == regionName) + { + Contexts.Remove(current); + Content = null; + } + } + } + public override void DeActivate(NavigationContext navigationContext) + { + if (Content is NavigationContext current) + { + if (current == navigationContext) + { + Contexts.Remove(current); + Content = null; + } + } } private void ViewContents_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/ItemsRegion.cs b/src/Lemon.ModuleNavigation.Avaloniaui/ItemsRegion.cs index 30d4eea..968961e 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/ItemsRegion.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/ItemsRegion.cs @@ -5,7 +5,7 @@ namespace Lemon.ModuleNavigation.Avaloniaui; -public class ItemsRegion : AvaloniauiRegion +public class ItemsRegion : Region { private readonly ItemsControl _itemsControl; public ItemsRegion(ItemsControl itemsControl, string name) @@ -84,9 +84,13 @@ public override void Activate(NavigationContext target) SelectedItem = target; } } - public override void DeActivate(NavigationContext target) + public override void DeActivate(string viewName) { - Contexts.Remove(target); + Contexts.Remove(Contexts.Last(c => c.TargetViewName == viewName)); + } + public override void DeActivate(NavigationContext navigationContext) + { + Contexts.Remove(navigationContext); } public void Add(NavigationContext item) { @@ -110,7 +114,7 @@ private void ViewContents_CollectionChanged(object? sender, NotifyCollectionChan { foreach (var item in e.OldItems) { - _itemsControl.Items.Remove(e.OldItems); + _itemsControl.Items.Remove(item); } } } diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/NavigationExtension.cs b/src/Lemon.ModuleNavigation.Avaloniaui/NavigationExtension.cs index 19f3fcc..6608ecd 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/NavigationExtension.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/NavigationExtension.cs @@ -36,7 +36,7 @@ void LoadedHandler(object? sender, RoutedEventArgs e) { var serviceProvider = navigationProvider!.ServiceProvider; var handler = serviceProvider.GetRequiredService(); - handler.RegionManager.AddRegion(currentValue, control.ToContainer(currentValue)); + handler.RegionManager.AddRegion(currentValue, control.ToRegion(currentValue)); } control.Loaded -= LoadedHandler; } @@ -112,7 +112,7 @@ public static void SetModuleContainerName(Control control, string value) #region CanUnloadProperty public static readonly AttachedProperty CanUnloadProperty = AvaloniaProperty.RegisterAttached("CanUnload", - defaultValue: true, + defaultValue: false, coerce: CoerceCanUnload); private static bool CoerceCanUnload(AvaloniaObject targetObject, bool currentValue) @@ -160,17 +160,31 @@ private static void UnloadModule(object? sender, RoutedEventArgs e) { if (sender is Button button) { + var view = button.FindLogicalAncestorOfType(includeSelf: false); + if (view != null) + { + } var tabItem = button.FindLogicalAncestorOfType(includeSelf: false) ?? throw new InvalidOperationException($"There is no 'TabItem' found in parents of {button}"); var tabContainer = tabItem.FindLogicalAncestorOfType(includeSelf: false); if (tabContainer != null) { - IModule item = tabItem.DataContext as IModule ?? throw new InvalidOperationException($"The DataContext of tabItem is not derived from IModule"); - if (item.CanUnload) + if (tabItem.DataContext is IModule item) + { + if (item.CanUnload) + { + if (tabContainer.DataContext is IServiceAware serviceAware) + { + var handler = serviceAware.ServiceProvider.GetRequiredService(); + handler.ModuleManager.ActiveModules.Remove(item); + } + } + } + else if (tabItem.DataContext is NavigationContext navigationContext) { if (tabContainer.DataContext is IServiceAware serviceAware) { - var handler = serviceAware.ServiceProvider.GetRequiredService(); - handler.ModuleManager.ActiveModules.Remove(item); + var regionManager = serviceAware.ServiceProvider.GetRequiredService(); + regionManager.RequestUnload(navigationContext); } } } diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/AvaloniauiRegion.cs b/src/Lemon.ModuleNavigation.Avaloniaui/Region.cs similarity index 95% rename from src/Lemon.ModuleNavigation.Avaloniaui/AvaloniauiRegion.cs rename to src/Lemon.ModuleNavigation.Avaloniaui/Region.cs index a07d3c0..942cc98 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/AvaloniauiRegion.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/Region.cs @@ -8,12 +8,12 @@ namespace Lemon.ModuleNavigation.Avaloniaui; -public abstract class AvaloniauiRegion : IRegion +public abstract class Region : IRegion { private readonly ConcurrentDictionary _viewCache = new(); private readonly ConcurrentItem<(IView View, INavigationAware NavigationAware)> _current = new(); - public AvaloniauiRegion() + public Region() { RegionTemplate = CreateRegionDataTemplate(); } @@ -24,6 +24,7 @@ public AvaloniauiRegion() public IDataTemplate? RegionTemplate { get; set; } public abstract void Activate(NavigationContext target); + public abstract void DeActivate(string viewName); public abstract void DeActivate(NavigationContext target); private IDataTemplate CreateRegionDataTemplate() diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/RegionsExtension.cs b/src/Lemon.ModuleNavigation.Avaloniaui/RegionsExtension.cs index 19782bc..f352fb1 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/RegionsExtension.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/RegionsExtension.cs @@ -5,7 +5,7 @@ namespace Lemon.ModuleNavigation.Avaloniaui; public static class RegionsExtension { - public static IRegion ToContainer(this Control control, string name) + public static IRegion ToRegion(this Control control, string name) { return control switch { diff --git a/src/Lemon.ModuleNavigation.Avaloniaui/TabRegion.cs b/src/Lemon.ModuleNavigation.Avaloniaui/TabRegion.cs index 5b5b460..e6c39d3 100644 --- a/src/Lemon.ModuleNavigation.Avaloniaui/TabRegion.cs +++ b/src/Lemon.ModuleNavigation.Avaloniaui/TabRegion.cs @@ -1,40 +1,64 @@ using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Data; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.CompilerServices; namespace Lemon.ModuleNavigation.Avaloniaui; -public class TabRegion : AvaloniauiRegion +public class TabRegion : Region, INotifyPropertyChanged { private readonly TabControl _tabControl; - public TabRegion(TabControl tabControl, string name) + public TabRegion(TabControl tabControl, string name) { _tabControl = tabControl; - _tabControl.ContentTemplate = RegionTemplate; Contexts = []; - Contexts.CollectionChanged += ViewContents_CollectionChanged; + //Contexts.CollectionChanged += ViewContents_CollectionChanged; + + + _tabControl.Bind(SelectingItemsControl.SelectedItemProperty, + new Binding(nameof(SelectedItem)) + { + Mode = BindingMode.TwoWay, + Source = this + }); + _tabControl.Bind(ItemsControl.ItemsSourceProperty, + new Binding(nameof(Contexts)) + { + Source = this + }); + _tabControl.ContentTemplate = RegionTemplate; + Name = name; } public override string Name { get; } - public object? SelectedItem + private NavigationContext? _selectItem; + public NavigationContext? SelectedItem { get { - return _tabControl.SelectedItem; + return _selectItem; } set { - _tabControl.SelectedItem = value; + _selectItem = value; + OnPropertyChanged(); } } public override ObservableCollection Contexts { get; } - + public event PropertyChangedEventHandler? PropertyChanged; + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } public override void Activate(NavigationContext target) { if (!target.RequestNew) @@ -63,9 +87,13 @@ public override void Activate(NavigationContext target) SelectedItem = target; } } - public override void DeActivate(NavigationContext target) + public override void DeActivate(string viewName) + { + Contexts.Remove(Contexts.Last(c => c.TargetViewName == viewName)); + } + public override void DeActivate(NavigationContext navigationContext) { - Contexts.Remove(target); + Contexts.Remove(navigationContext); } public void Add(NavigationContext item) { @@ -89,7 +117,7 @@ private void ViewContents_CollectionChanged(object? sender, NotifyCollectionChan { foreach (var item in e.OldItems) { - _tabControl.Items.Remove(e.OldItems); + _tabControl.Items.Remove(item); } } } diff --git a/src/Lemon.ModuleNavigation.Sample/Views/ViewAlpha.axaml b/src/Lemon.ModuleNavigation.Sample/Views/ViewAlpha.axaml index f10423d..d5bc2d4 100644 --- a/src/Lemon.ModuleNavigation.Sample/Views/ViewAlpha.axaml +++ b/src/Lemon.ModuleNavigation.Sample/Views/ViewAlpha.axaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:lm="https://github.com/NeverMorewd/Lemon.ModuleNavigation" d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> @@ -16,6 +17,12 @@ Command="{Binding CloseCommand}" Content="CloseDialog" IsVisible="{Binding IsDialog}" /> +