From c1f4c6e899626732f8c65ae0d48b072d66b4fe75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 1 Jul 2025 17:54:33 +0000 Subject: [PATCH 1/5] Initial plan From b469cd3a26eccbd92d4a9e24ac2c4e9977d5badd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 1 Jul 2025 18:04:08 +0000 Subject: [PATCH 2/5] Implement window title synchronization with navigation bar header Co-authored-by: OmidID <956077+OmidID@users.noreply.github.com> --- .../AvaloniaInside.Shell.csproj | 2 +- src/AvaloniaInside.Shell/HostedItemsHelper.cs | 33 +++++++++++++------ src/AvaloniaInside.Shell/NavigationStack.cs | 15 ++++++--- .../ShellExample/Views/MainWindow.axaml | 2 +- .../ShellExample/Views/MainWindow.axaml.cs | 22 +++++++++++++ 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj index ada87c5..a08279d 100644 --- a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj +++ b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj @@ -1,6 +1,6 @@ - net8.0;net9.0 + net8.0 enable latest 1.3.2 diff --git a/src/AvaloniaInside.Shell/HostedItemsHelper.cs b/src/AvaloniaInside.Shell/HostedItemsHelper.cs index 683f487..9eb90e3 100644 --- a/src/AvaloniaInside.Shell/HostedItemsHelper.cs +++ b/src/AvaloniaInside.Shell/HostedItemsHelper.cs @@ -7,30 +7,43 @@ namespace AvaloniaInside.Shell; public static class HostedItemsHelper { - private class ItemsControlProxy(ItemsControl itemsControl) : IHostItems + private class ItemsControlProxy : IHostItems { + private readonly ItemsControl _itemsControl; + + public ItemsControlProxy(ItemsControl itemsControl) + { + _itemsControl = itemsControl; + } + public IEnumerable? ItemsSource { - get => itemsControl.ItemsSource; - set => itemsControl.ItemsSource = value; + get => _itemsControl.ItemsSource; + set => _itemsControl.ItemsSource = value; } - public ItemCollection Items => itemsControl.Items; + public ItemCollection Items => _itemsControl.Items; } - private class SelectingItemsControlProxy(SelectingItemsControl itemsControl) - : ItemsControlProxy(itemsControl), ISelectableHostItems + private class SelectingItemsControlProxy : ItemsControlProxy, ISelectableHostItems { + private readonly SelectingItemsControl _selectingItemsControl; + + public SelectingItemsControlProxy(SelectingItemsControl itemsControl) : base(itemsControl) + { + _selectingItemsControl = itemsControl; + } + public event EventHandler? SelectionChanged { - add => itemsControl.SelectionChanged += value; - remove => itemsControl.SelectionChanged -= value; + add => _selectingItemsControl.SelectionChanged += value; + remove => _selectingItemsControl.SelectionChanged -= value; } public object? SelectedItem { - get => itemsControl.SelectedItem; - set => itemsControl.SelectedItem = value; + get => _selectingItemsControl.SelectedItem; + set => _selectingItemsControl.SelectedItem = value; } } diff --git a/src/AvaloniaInside.Shell/NavigationStack.cs b/src/AvaloniaInside.Shell/NavigationStack.cs index 431c366..d9b5e12 100644 --- a/src/AvaloniaInside.Shell/NavigationStack.cs +++ b/src/AvaloniaInside.Shell/NavigationStack.cs @@ -4,8 +4,15 @@ namespace AvaloniaInside.Shell; -public class NavigationStack(INavigationViewLocator viewLocator) +public class NavigationStack { + private readonly INavigationViewLocator _viewLocator; + + public NavigationStack(INavigationViewLocator viewLocator) + { + _viewLocator = viewLocator; + } + public NavigationChain? Current { get; set; } public NavigationStackChanges Push( @@ -260,7 +267,7 @@ private void AscendingHostVerification(NavigationStackChanges changes, Navigatio Back = chain.Back, Node = parentNode, Type = NavigateType.Normal, - Instance = viewLocator.GetView(parentNode), + Instance = _viewLocator.GetView(parentNode), Uri = new Uri(chain.Uri, parentNode.Route) }; changes.NewNavigationChains.Add(parentChain); @@ -297,7 +304,7 @@ private void VerifyHostInitialised( hostChildChain.Back = parentChain; hostChildChain.Node = hostChildNode; hostChildChain.Type = NavigateType.Normal; - hostChildChain.Instance = viewLocator.GetView(hostChildNode); + hostChildChain.Instance = _viewLocator.GetView(hostChildNode); hostChildChain.Uri = new Uri(chain.Uri, hostChildNode.Route); hostChildChain.Hosted = true; @@ -313,7 +320,7 @@ private NavigationChain NewInstanceAndChain( NavigateType type, NavigationChain? back) { - var instance = viewLocator.GetView(node); + var instance = _viewLocator.GetView(node); var chain = new NavigationChain { Node = node, diff --git a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml index 70ee737..34e2a51 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml +++ b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml @@ -8,5 +8,5 @@ Icon="/Assets/avalonia-logo.ico" Title="ShellExample" Width="450"> - + diff --git a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs index f9a4814..dae96f0 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs +++ b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs @@ -1,5 +1,7 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Interactivity; +using AvaloniaInside.Shell; namespace ShellExample.Views; @@ -11,4 +13,24 @@ public MainWindow() InitializeComponent(); } + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + if (MainView.ContentView != null) + { + MainView.ContentView.PropertyChanged += (sender, args) => + { + if (args.Property == StackContentView.CurrentViewProperty) + { + if (args.NewValue is AvaloniaObject newValue) + { + var header = NavigationBar.GetHeader(newValue) as string; + Title = header ?? "Shell Example"; + System.Diagnostics.Debug.WriteLine($"Window title updated to: {Title}"); + } + } + }; + } + } } From e264afd826dbacee7947aa7fcb540da64954b9e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 1 Jul 2025 18:06:04 +0000 Subject: [PATCH 3/5] Clean up implementation and restore original target frameworks Co-authored-by: OmidID <956077+OmidID@users.noreply.github.com> --- src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj | 2 +- src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj index a08279d..ada87c5 100644 --- a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj +++ b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj @@ -1,6 +1,6 @@ - net8.0 + net8.0;net9.0 enable latest 1.3.2 diff --git a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs index dae96f0..8734894 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs +++ b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs @@ -27,7 +27,6 @@ protected override void OnLoaded(RoutedEventArgs e) { var header = NavigationBar.GetHeader(newValue) as string; Title = header ?? "Shell Example"; - System.Diagnostics.Debug.WriteLine($"Window title updated to: {Title}"); } } }; From 305d67cae8466efe4812c09859c94563bac9b12e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 2 Jul 2025 18:22:31 +0000 Subject: [PATCH 4/5] Implement OnNavigate event and revert primary constructor changes Co-authored-by: OmidID <956077+OmidID@users.noreply.github.com> --- .../AvaloniaInside.Shell.csproj | 2 +- src/AvaloniaInside.Shell/HostedItemsHelper.cs | 33 ++++++----------- src/AvaloniaInside.Shell/INavigator.cs | 2 ++ src/AvaloniaInside.Shell/NavigationStack.cs | 15 +++----- src/AvaloniaInside.Shell/Navigator.cs | 16 +++++++++ .../ShellExample/Views/MainWindow.axaml.cs | 35 ++++++++++++------- 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj index ada87c5..0eb8790 100644 --- a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj +++ b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj @@ -1,6 +1,6 @@ - net8.0;net9.0 + net8.0 enable latest 1.3.2 diff --git a/src/AvaloniaInside.Shell/HostedItemsHelper.cs b/src/AvaloniaInside.Shell/HostedItemsHelper.cs index 9eb90e3..683f487 100644 --- a/src/AvaloniaInside.Shell/HostedItemsHelper.cs +++ b/src/AvaloniaInside.Shell/HostedItemsHelper.cs @@ -7,43 +7,30 @@ namespace AvaloniaInside.Shell; public static class HostedItemsHelper { - private class ItemsControlProxy : IHostItems + private class ItemsControlProxy(ItemsControl itemsControl) : IHostItems { - private readonly ItemsControl _itemsControl; - - public ItemsControlProxy(ItemsControl itemsControl) - { - _itemsControl = itemsControl; - } - public IEnumerable? ItemsSource { - get => _itemsControl.ItemsSource; - set => _itemsControl.ItemsSource = value; + get => itemsControl.ItemsSource; + set => itemsControl.ItemsSource = value; } - public ItemCollection Items => _itemsControl.Items; + public ItemCollection Items => itemsControl.Items; } - private class SelectingItemsControlProxy : ItemsControlProxy, ISelectableHostItems + private class SelectingItemsControlProxy(SelectingItemsControl itemsControl) + : ItemsControlProxy(itemsControl), ISelectableHostItems { - private readonly SelectingItemsControl _selectingItemsControl; - - public SelectingItemsControlProxy(SelectingItemsControl itemsControl) : base(itemsControl) - { - _selectingItemsControl = itemsControl; - } - public event EventHandler? SelectionChanged { - add => _selectingItemsControl.SelectionChanged += value; - remove => _selectingItemsControl.SelectionChanged -= value; + add => itemsControl.SelectionChanged += value; + remove => itemsControl.SelectionChanged -= value; } public object? SelectedItem { - get => _selectingItemsControl.SelectedItem; - set => _selectingItemsControl.SelectedItem = value; + get => itemsControl.SelectedItem; + set => itemsControl.SelectedItem = value; } } diff --git a/src/AvaloniaInside.Shell/INavigator.cs b/src/AvaloniaInside.Shell/INavigator.cs index 18d03a5..d8f4e90 100644 --- a/src/AvaloniaInside.Shell/INavigator.cs +++ b/src/AvaloniaInside.Shell/INavigator.cs @@ -9,6 +9,8 @@ public interface INavigator { Uri CurrentUri { get; } + event EventHandler? OnNavigate; + INavigationRegistrar Registrar { get; } NavigationChain? CurrentChain { get; } diff --git a/src/AvaloniaInside.Shell/NavigationStack.cs b/src/AvaloniaInside.Shell/NavigationStack.cs index d9b5e12..431c366 100644 --- a/src/AvaloniaInside.Shell/NavigationStack.cs +++ b/src/AvaloniaInside.Shell/NavigationStack.cs @@ -4,15 +4,8 @@ namespace AvaloniaInside.Shell; -public class NavigationStack +public class NavigationStack(INavigationViewLocator viewLocator) { - private readonly INavigationViewLocator _viewLocator; - - public NavigationStack(INavigationViewLocator viewLocator) - { - _viewLocator = viewLocator; - } - public NavigationChain? Current { get; set; } public NavigationStackChanges Push( @@ -267,7 +260,7 @@ private void AscendingHostVerification(NavigationStackChanges changes, Navigatio Back = chain.Back, Node = parentNode, Type = NavigateType.Normal, - Instance = _viewLocator.GetView(parentNode), + Instance = viewLocator.GetView(parentNode), Uri = new Uri(chain.Uri, parentNode.Route) }; changes.NewNavigationChains.Add(parentChain); @@ -304,7 +297,7 @@ private void VerifyHostInitialised( hostChildChain.Back = parentChain; hostChildChain.Node = hostChildNode; hostChildChain.Type = NavigateType.Normal; - hostChildChain.Instance = _viewLocator.GetView(hostChildNode); + hostChildChain.Instance = viewLocator.GetView(hostChildNode); hostChildChain.Uri = new Uri(chain.Uri, hostChildNode.Route); hostChildChain.Hosted = true; @@ -320,7 +313,7 @@ private NavigationChain NewInstanceAndChain( NavigateType type, NavigationChain? back) { - var instance = _viewLocator.GetView(node); + var instance = viewLocator.GetView(node); var chain = new NavigationChain { Node = node, diff --git a/src/AvaloniaInside.Shell/Navigator.cs b/src/AvaloniaInside.Shell/Navigator.cs index d189083..f993d24 100644 --- a/src/AvaloniaInside.Shell/Navigator.cs +++ b/src/AvaloniaInside.Shell/Navigator.cs @@ -18,6 +18,8 @@ public partial class Navigator : INavigator private bool _navigating; private ShellView? _shellView; + public event EventHandler? OnNavigate; + public ShellView ShellView => _shellView ?? throw new ArgumentNullException(nameof(ShellView)); public Uri CurrentUri => _stack.Current?.Uri ?? Registrar.RootUri; @@ -154,6 +156,20 @@ await _updateStrategy.UpdateChangesAsync( await fromPage.OnNavigateAsync(args, cancellationToken); } + // Fire the OnNavigate event for external subscribers + OnNavigate?.Invoke(this, new NaviagateEventArgs + { + Sender = sender, + From = fromPage, + To = _stack.Current?.Instance, + FromUri = origin, + ToUri = newUri, + Argument = argument, + Navigate = finalNavigateType, + WithAnimation = withAnimation, + OverrideTransition = overrideTransition + }); + _navigating = false; } diff --git a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs index 8734894..06958c6 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs +++ b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml.cs @@ -17,19 +17,30 @@ protected override void OnLoaded(RoutedEventArgs e) { base.OnLoaded(e); - if (MainView.ContentView != null) + // Subscribe to navigation events to update window title + if (MainView.Navigator != null) { - MainView.ContentView.PropertyChanged += (sender, args) => - { - if (args.Property == StackContentView.CurrentViewProperty) - { - if (args.NewValue is AvaloniaObject newValue) - { - var header = NavigationBar.GetHeader(newValue) as string; - Title = header ?? "Shell Example"; - } - } - }; + MainView.Navigator.OnNavigate += OnNavigate; + } + } + + protected override void OnUnloaded(RoutedEventArgs e) + { + // Unsubscribe from navigation events + if (MainView.Navigator != null) + { + MainView.Navigator.OnNavigate -= OnNavigate; + } + + base.OnUnloaded(e); + } + + private void OnNavigate(object? sender, NaviagateEventArgs e) + { + if (e.To is AvaloniaObject targetView) + { + var header = NavigationBar.GetHeader(targetView) as string; + Title = header ?? "Shell Example"; } } } From 3abf81dc0fb8860fd1cfa06c5da3ec31f15320b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 2 Jul 2025 18:23:13 +0000 Subject: [PATCH 5/5] Restore original target frameworks Co-authored-by: OmidID <956077+OmidID@users.noreply.github.com> --- src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj index 0eb8790..ada87c5 100644 --- a/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj +++ b/src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj @@ -1,6 +1,6 @@ - net8.0 + net8.0;net9.0 enable latest 1.3.2