From ef0e5f31e198c2bebd168ffa12f22fd8b6e250b9 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 18:01:38 +0600 Subject: [PATCH 01/27] nullable annotation --- .../Controls/Navigation/INavigationView.cs | 41 +++------- .../Navigation/INavigationViewItem.cs | 8 +- .../Navigation/NavigationView.Base.cs | 7 +- .../Navigation/NavigationView.Parent.cs | 3 +- .../Navigation/NavigationView.Properties.cs | 82 ++++++------------- .../NavigationView.TemplateParts.cs | 61 +++++++------- .../Controls/Navigation/NavigationViewItem.cs | 46 ++++------- 7 files changed, 86 insertions(+), 162 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/INavigationView.cs b/src/Wpf.Ui/Controls/Navigation/INavigationView.cs index 7861d8408..819425342 100644 --- a/src/Wpf.Ui/Controls/Navigation/INavigationView.cs +++ b/src/Wpf.Ui/Controls/Navigation/INavigationView.cs @@ -23,7 +23,7 @@ public interface INavigationView /// /// Gets or sets the header content. /// - object Header { get; set; } + object? Header { get; set; } /// /// Gets or sets the visibility. @@ -43,7 +43,7 @@ public interface INavigationView /// /// Gets or sets an object source used to generate the content of the NavigationView menu. /// - object MenuItemsSource { get; set; } + object? MenuItemsSource { get; set; } /// /// Gets the list of objects to be used as navigation items in the footer menu. @@ -53,7 +53,7 @@ public interface INavigationView /// /// Gets or sets the object that represents the navigation items to be used in the footer menu. /// - object FooterMenuItemsSource { get; set; } + object? FooterMenuItemsSource { get; set; } /// /// Gets the selected item. @@ -63,7 +63,7 @@ public interface INavigationView /// /// Gets or sets a UI element that is shown at the top of the control, below the pane if PaneDisplayMode is Top. /// - object ContentOverlay { get; set; } + object? ContentOverlay { get; set; } /// /// Gets a value that indicates whether the back button is enabled or disabled. @@ -99,12 +99,12 @@ public interface INavigationView /// /// Gets or sets the content for the pane header. /// - object PaneHeader { get; set; } + object? PaneHeader { get; set; } /// /// Gets or sets the content for the pane footer. /// - object PaneFooter { get; set; } + object? PaneFooter { get; set; } /// /// Gets a value that specifies how the pane and content areas of a NavigationView are being shown. @@ -115,17 +115,17 @@ public interface INavigationView /// /// Gets or sets an AutoSuggestBox to be displayed in the NavigationView. /// - AutoSuggestBox AutoSuggestBox { get; set; } + AutoSuggestBox? AutoSuggestBox { get; set; } /// /// Gets or sets an TitleBar to be displayed in the NavigationView. /// - TitleBar TitleBar { get; set; } + TitleBar? TitleBar { get; set; } /// /// Template Property for and . /// - ControlTemplate ItemTemplate { get; set; } + ControlTemplate? ItemTemplate { get; set; } /// /// Gets or sets a value deciding how long the effect of the transition between the pages should take. @@ -171,25 +171,13 @@ public interface INavigationView /// Synchronously navigates current navigation Frame to the /// given Element. /// - bool Navigate(Type pageType); + bool Navigate(Type pageType, object? dataContext = null); /// /// Synchronously navigates current navigation Frame to the /// given Element. /// - bool Navigate(Type pageType, object dataContext); - - /// - /// Synchronously navigates current navigation Frame to the - /// given Element. - /// - bool Navigate(string pageIdOrTargetTag); - - /// - /// Synchronously navigates current navigation Frame to the - /// given Element. - /// - bool Navigate(string pageIdOrTargetTag, object dataContext); + bool Navigate(string pageIdOrTargetTag, object? dataContext = null); /// /// Replaces the contents of the navigation frame, without changing the currently selected item or triggering an . @@ -199,12 +187,7 @@ public interface INavigationView /// /// Replaces the contents of the navigation frame, without changing the currently selected item or triggering an . /// - bool ReplaceContent(UIElement pageInstanceToEmbed); - - /// - /// Replaces the contents of the navigation frame, without changing the currently selected item or triggering an . - /// - bool ReplaceContent(UIElement pageInstanceToEmbed, object dataContext); + bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataContext = null); /// /// Navigates the NavigationView to the next journal entry. diff --git a/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs b/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs index 1ec705092..07bf5c25b 100644 --- a/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs +++ b/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs @@ -28,7 +28,7 @@ public interface INavigationViewItem /// Gets or sets the icon displayed in the MenuItem object. /// If it's a , additional effects will be applied. /// - object Icon { get; set; } + object? Icon { get; set; } /// /// Gets the collection of menu items displayed in the NavigationView. @@ -38,7 +38,7 @@ public interface INavigationViewItem /// /// Gets or sets an object source used to generate the content of the NavigationView menu. /// - object MenuItemsSource { get; set; } + object? MenuItemsSource { get; set; } /// /// Gets information whether the current element is active. @@ -58,12 +58,12 @@ public interface INavigationViewItem /// /// The type of the page to be navigated. (Should be derived from ). /// - public Type TargetPageType { get; set; } + public Type? TargetPageType { get; set; } /// /// Template Property /// - public ControlTemplate Template { get; set; } + public ControlTemplate? Template { get; set; } /// /// Add / Remove ClickEvent handler. diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index d8906e2c9..1681acc62 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -39,7 +39,6 @@ static NavigationView() public NavigationView() { - SelectedItem = null; NavigationParent = this; SetValue(MenuItemsProperty, @@ -93,11 +92,7 @@ private void OnLoaded(object sender, RoutedEventArgs e) /// protected virtual void OnUnloaded(object sender, RoutedEventArgs e) { - if (MenuItems is INotifyCollectionChanged menuItemsCollection) - menuItemsCollection.CollectionChanged -= OnMenuItemsCollectionChanged; - - if (FooterMenuItems is INotifyCollectionChanged footerMenuItemsCollection) - footerMenuItemsCollection.CollectionChanged -= OnFooterMenuItemsCollectionChanged; + NavigationViewContentPresenter.Navigated -= OnNavigationViewContentPresenterNavigated; } /// diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Parent.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Parent.cs index ffe8f0b0e..ba4595976 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Parent.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Parent.cs @@ -33,8 +33,7 @@ internal INavigationView NavigationParent /// /// /// Instance of the or . - internal static NavigationView? GetNavigationParent(T navigationItem) - where T : DependencyObject, INavigationViewItem + internal static NavigationView? GetNavigationParent(T navigationItem) where T : DependencyObject, INavigationViewItem { if (navigationItem.GetValue(NavigationParentProperty) is NavigationView navigationView) return navigationView; diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs index 0b0ecabf2..e72c3ae0a 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs @@ -22,14 +22,14 @@ public partial class NavigationView /// public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . /// public static readonly DependencyProperty HeaderVisibilityProperty = DependencyProperty.Register(nameof(HeaderVisibility), typeof(Visibility), typeof(NavigationView), - new FrameworkPropertyMetadata(System.Windows.Visibility.Visible)); + new FrameworkPropertyMetadata(Visibility.Visible)); /// /// Property for . @@ -50,7 +50,7 @@ public partial class NavigationView /// public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.Register(nameof(MenuItemsSource), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!), OnMenuItemsSourcePropertyChanged)); + new FrameworkPropertyMetadata(null, OnMenuItemsSourcePropertyChanged)); /// /// Property for . @@ -64,14 +64,14 @@ public partial class NavigationView /// public static readonly DependencyProperty FooterMenuItemsSourceProperty = DependencyProperty.Register(nameof(FooterMenuItemsSource), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!), OnFooterMenuItemsSourcePropertyChanged)); + new FrameworkPropertyMetadata(null, OnFooterMenuItemsSourcePropertyChanged)); /// /// Property for . /// public static readonly DependencyProperty ContentOverlayProperty = DependencyProperty.Register(nameof(ContentOverlay), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . @@ -120,14 +120,14 @@ public partial class NavigationView /// public static readonly DependencyProperty PaneHeaderProperty = DependencyProperty.Register(nameof(PaneHeader), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . /// public static readonly DependencyProperty PaneFooterProperty = DependencyProperty.Register(nameof(PaneFooter), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(((object)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . @@ -141,14 +141,14 @@ public partial class NavigationView /// public static readonly DependencyProperty AutoSuggestBoxProperty = DependencyProperty.Register(nameof(AutoSuggestBox), typeof(AutoSuggestBox), typeof(NavigationView), - new FrameworkPropertyMetadata(((AutoSuggestBox)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . /// public static readonly DependencyProperty TitleBarProperty = DependencyProperty.Register(nameof(TitleBar), typeof(TitleBar), typeof(NavigationView), - new FrameworkPropertyMetadata(((TitleBar)null!))); + new FrameworkPropertyMetadata(null)); /// /// Property for . @@ -175,7 +175,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(TransitionType.FadeInWithSlide)); /// - public object Header + public object? Header { get => GetValue(HeaderProperty); set => SetValue(HeaderProperty, value); @@ -204,7 +204,7 @@ public IList? MenuItems /// [Bindable(true)] - public object MenuItemsSource + public object? MenuItemsSource { get => GetValue(MenuItemsSourceProperty); set @@ -225,7 +225,7 @@ public IList? FooterMenuItems /// [Bindable(true)] - public object FooterMenuItemsSource + public object? FooterMenuItemsSource { get => GetValue(FooterMenuItemsSourceProperty); set @@ -238,7 +238,7 @@ public object FooterMenuItemsSource } /// - public object ContentOverlay + public object? ContentOverlay { get => GetValue(ContentOverlayProperty); set => SetValue(ContentOverlayProperty, value); @@ -287,14 +287,14 @@ public double OpenPaneLength } /// - public object PaneHeader + public object? PaneHeader { get => GetValue(PaneHeaderProperty); set => SetValue(PaneHeaderProperty, value); } /// - public object PaneFooter + public object? PaneFooter { get => GetValue(PaneFooterProperty); set => SetValue(PaneFooterProperty, value); @@ -308,21 +308,21 @@ public NavigationViewPaneDisplayMode PaneDisplayMode } /// - public AutoSuggestBox AutoSuggestBox + public AutoSuggestBox? AutoSuggestBox { get => (AutoSuggestBox)GetValue(AutoSuggestBoxProperty); set => SetValue(AutoSuggestBoxProperty, value); } /// - public TitleBar TitleBar + public TitleBar? TitleBar { get => (TitleBar)GetValue(TitleBarProperty); set => SetValue(TitleBarProperty, value); } /// - public ControlTemplate ItemTemplate + public ControlTemplate? ItemTemplate { get => (ControlTemplate)GetValue(ItemTemplateProperty); set => SetValue(ItemTemplateProperty, value); @@ -348,66 +348,34 @@ private static void OnMenuItemsPropertyChanged(DependencyObject? d, DependencyPr if (d is not NavigationView navigationView) return; - if (e.OldValue is INotifyCollectionChanged oldMenuItemsCollection) - oldMenuItemsCollection.CollectionChanged -= navigationView.OnMenuItemsCollectionChanged; - - if (e.NewValue is INotifyCollectionChanged newMenuItemsCollection) - newMenuItemsCollection.CollectionChanged += navigationView.OnMenuItemsCollectionChanged; - navigationView.OnMenuItemsChanged(); } - protected virtual void OnMenuItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) - { - } - - private static void OnMenuItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnMenuItemsSourcePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { - if (d is not NavigationView navigationView) - return; - - if (e.NewValue is not IList enumerableNewValue) + if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) return; - if (navigationView.MenuItems != null) - navigationView.MenuItems = null; - navigationView.MenuItems = enumerableNewValue; } - private static void OnFooterMenuItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnFooterMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) return; - if (e.OldValue is INotifyCollectionChanged oldMenuItemsCollection) - oldMenuItemsCollection.CollectionChanged -= navigationView.OnFooterMenuItemsCollectionChanged; - - if (e.NewValue is INotifyCollectionChanged newMenuItemsCollection) - newMenuItemsCollection.CollectionChanged += navigationView.OnFooterMenuItemsCollectionChanged; - navigationView.OnFooterMenuItemsChanged(); } - private static void OnFooterMenuItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnFooterMenuItemsSourcePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { - if (d is not NavigationView navigationView) - return; - - if (e.NewValue is not IList enumerableNewValue) + if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) return; - if (navigationView.FooterMenuItems != null) - navigationView.FooterMenuItems = null; - navigationView.FooterMenuItems = enumerableNewValue; } - protected virtual void OnFooterMenuItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - } - - private static void OnPaneDisplayModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnPaneDisplayModePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) return; @@ -415,7 +383,7 @@ private static void OnPaneDisplayModePropertyChanged(DependencyObject d, Depende navigationView.OnPaneDisplayModeChanged(); } - private static void OnItemTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnItemTemplatePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) return; diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs index 84efd5bad..282ad79b3 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs @@ -6,15 +6,16 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. +using System; using System.Windows; namespace Wpf.Ui.Controls.Navigation; -[TemplatePart(Name = "PART_NavigationViewContentPresenter", Type = typeof(NavigationViewContentPresenter))] -[TemplatePart(Name = "PART_MenuItemsItemsControl", Type = typeof(System.Windows.Controls.ItemsControl))] -[TemplatePart(Name = "PART_FooterMenuItemsItemsControl", Type = typeof(System.Windows.Controls.ItemsControl))] -[TemplatePart(Name = "PART_BackButton", Type = typeof(System.Windows.Controls.Button))] -[TemplatePart(Name = "PART_ToggleButton", Type = typeof(System.Windows.Controls.Button))] +[TemplatePart(Name = TemplateElementNavigationViewContentPresenter, Type = typeof(NavigationViewContentPresenter))] +[TemplatePart(Name = TemplateElementMenuItemsItemsControl, Type = typeof(System.Windows.Controls.ItemsControl))] +[TemplatePart(Name = TemplateElementFooterMenuItemsItemsControl, Type = typeof(System.Windows.Controls.ItemsControl))] +[TemplatePart(Name = TemplateElementBackButton, Type = typeof(System.Windows.Controls.Button))] +[TemplatePart(Name = TemplateElementToggleButton, Type = typeof(System.Windows.Controls.Button))] public partial class NavigationView { /// @@ -45,67 +46,63 @@ public partial class NavigationView /// /// Control responsible for rendering the content. /// - protected NavigationViewContentPresenter NavigationViewContentPresenter; + protected NavigationViewContentPresenter NavigationViewContentPresenter = null!; /// /// Control located at the top of the pane with left arrow icon. /// - protected System.Windows.Controls.ItemsControl MenuItemsItemsControl; + protected System.Windows.Controls.ItemsControl MenuItemsItemsControl = null!; /// /// Control located at the top of the pane with hamburger icon. /// - protected System.Windows.Controls.ItemsControl FooterMenuItemsItemsControl; + protected System.Windows.Controls.ItemsControl FooterMenuItemsItemsControl = null!; /// /// Control located at the top of the pane with left arrow icon. /// - protected System.Windows.Controls.Button BackButton; + protected System.Windows.Controls.Button? BackButton; /// /// Control located at the top of the pane with hamburger icon. /// - protected System.Windows.Controls.Button ToggleButton; + protected System.Windows.Controls.Button? ToggleButton; /// public override void OnApplyTemplate() { base.OnApplyTemplate(); - if (GetTemplateChild(TemplateElementNavigationViewContentPresenter) is NavigationViewContentPresenter navigationViewContentPresenter) - NavigationViewContentPresenter = navigationViewContentPresenter; + NavigationViewContentPresenter = GetTemplateChild(TemplateElementNavigationViewContentPresenter); + MenuItemsItemsControl = GetTemplateChild(TemplateElementMenuItemsItemsControl); + FooterMenuItemsItemsControl = GetTemplateChild(TemplateElementFooterMenuItemsItemsControl); - if (GetTemplateChild(TemplateElementMenuItemsItemsControl) is System.Windows.Controls.ItemsControl menuItemsItemsControl) - MenuItemsItemsControl = menuItemsItemsControl; - - if (GetTemplateChild(TemplateElementFooterMenuItemsItemsControl) is System.Windows.Controls.ItemsControl footerMenuItemsItemsControl) - FooterMenuItemsItemsControl = footerMenuItemsItemsControl; + NavigationViewContentPresenter.Navigated += OnNavigationViewContentPresenterNavigated; + MenuItemsItemsControl.ItemsSource = MenuItems; + FooterMenuItemsItemsControl.ItemsSource = FooterMenuItems; if (GetTemplateChild(TemplateElementBackButton) is System.Windows.Controls.Button backButton) + { BackButton = backButton; - if (GetTemplateChild(TemplateElementToggleButton) is System.Windows.Controls.Button toggleButton) - ToggleButton = toggleButton; - - if (NavigationViewContentPresenter != null) - NavigationViewContentPresenter.Navigated += OnNavigationViewContentPresenterNavigated; - - if (MenuItemsItemsControl != null) - MenuItemsItemsControl.ItemsSource = MenuItems; - - if (FooterMenuItemsItemsControl != null) - FooterMenuItemsItemsControl.ItemsSource = FooterMenuItems; - - if (BackButton != null) - { BackButton.Click -= OnBackButtonClick; BackButton.Click += OnBackButtonClick; } - if (ToggleButton != null) + if (GetTemplateChild(TemplateElementToggleButton) is System.Windows.Controls.Button toggleButton) { + ToggleButton = toggleButton; + ToggleButton.Click -= OnToggleButtonClick; ToggleButton.Click += OnToggleButtonClick; } } + + protected T GetTemplateChild(string name) where T : DependencyObject + { + if (GetTemplateChild(name) is not T dependencyObject) + throw new ArgumentNullException(name); + + return dependencyObject; + } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs index fc550cee3..cdbe14364 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs @@ -86,7 +86,7 @@ public IList? MenuItems /// [Bindable(true)] - public object MenuItemsSource + public object? MenuItemsSource { get => GetValue(MenuItemsSourceProperty); set @@ -126,7 +126,7 @@ public bool IsExpanded /// [Bindable(true), Category("Appearance")] - public object Icon + public object? Icon { get => GetValue(IconProperty); set => SetValue(IconProperty, value); @@ -140,7 +140,7 @@ public string TargetPageTag } /// - public Type TargetPageType + public Type? TargetPageType { get => (Type)GetValue(TargetPageTypeProperty); set => SetValue(TargetPageTypeProperty, value); @@ -158,16 +158,14 @@ public NavigationViewItem() { Id = Guid.NewGuid().ToString("n"); - SetValue(MenuItemsProperty, - new ObservableCollection()); + SetValue(MenuItemsProperty, new ObservableCollection()); } public NavigationViewItem(string name, SymbolRegular icon, Type targetPageType) { Id = Guid.NewGuid().ToString("n"); - SetValue(MenuItemsProperty, - new ObservableCollection()); + SetValue(MenuItemsProperty, new ObservableCollection()); SetValue(ContentProperty, name); SetValue(IconProperty, new SymbolIcon { Symbol = icon }); SetValue(TargetPageTypeProperty, targetPageType); @@ -178,19 +176,8 @@ protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); - if (MenuItems?.Count > 0) - HasMenuItems = true; - - if (MenuItemsSource is IList menuItemsSourceList) - { - if (MenuItems != null) - MenuItems = null; - - MenuItems = menuItemsSourceList; - } - - if (String.IsNullOrWhiteSpace(TargetPageTag)) - TargetPageTag = Content?.ToString()!.ToLower()!.Trim() ?? String.Empty; + if (string.IsNullOrWhiteSpace(TargetPageTag)) + TargetPageTag = Content?.ToString().ToLower().Trim() ?? string.Empty; } /// @@ -206,7 +193,7 @@ protected override void OnClick() } /// - /// Is called when mouse is cliked down. + /// Is called when mouse is clicked down. /// protected override void OnMouseDown(MouseButtonEventArgs e) { @@ -224,12 +211,11 @@ protected override void OnMouseDown(MouseButtonEventArgs e) return; } - var parentNativagionView = NavigationView.GetNavigationParent(this); + var parentNavigationView = NavigationView.GetNavigationParent(this); - if (parentNativagionView?.IsPaneOpen ?? false || parentNativagionView?.PaneDisplayMode != NavigationViewPaneDisplayMode.Left) + if (parentNavigationView?.IsPaneOpen ?? parentNavigationView?.PaneDisplayMode != NavigationViewPaneDisplayMode.Left) { base.OnMouseDown(e); - return; } @@ -238,7 +224,6 @@ protected override void OnMouseDown(MouseButtonEventArgs e) if (!mouseOverChevron) { base.OnMouseDown(e); - return; } @@ -259,15 +244,12 @@ private static void OnMenuItemsPropertyChanged(DependencyObject d, DependencyPro private static void OnMenuItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is not NavigationViewItem navigationViewItem) - return; - - if (e.NewValue is not IList enumerableNewValue) + if (d is not NavigationViewItem navigationViewItem || e.NewValue is not IList enumerableNewValue) return; - if (navigationViewItem.MenuItems != null) - navigationViewItem.MenuItems = null; - navigationViewItem.MenuItems = enumerableNewValue; + + if (navigationViewItem.MenuItems?.Count > 0) + navigationViewItem.HasMenuItems = true; } } From caf8faf8702fa00fef9be4012eb5d89d5c324973 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 18:45:54 +0600 Subject: [PATCH 02/27] removed duplicated code in NavigationView.Base --- .../Navigation/NavigationView.Base.cs | 234 ++++++++---------- .../Navigation/NavigationView.Properties.cs | 4 +- 2 files changed, 110 insertions(+), 128 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index 1681acc62..7a68cb487 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -11,6 +11,7 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; using System.Windows; namespace Wpf.Ui.Controls.Navigation; @@ -24,7 +25,7 @@ namespace Wpf.Ui.Controls.Navigation; [System.Drawing.ToolboxBitmap(typeof(NavigationView), "NavigationView.bmp")] public partial class NavigationView : System.Windows.Controls.Control, INavigationView { - private ObservableCollection? _autoSuggestBoxItems; + private ObservableCollection _autoSuggestBoxItems = new(); /// public INavigationViewItem? SelectedItem { get; private set; } @@ -57,28 +58,20 @@ protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); - if (ItemTemplate != null) - UpdateMenuItemsTemplate(); - if (Header is NavigationViewBreadcrumb navigationViewBreadcrumb) navigationViewBreadcrumb.NavigationView = this; - if (MenuItems?.Count > 0) - OnMenuItemsChanged(); - - if (MenuItemsSource is IList menuItemsSourceList) + if (AutoSuggestBox is not null) { - if (MenuItems != null) - MenuItems = null; - - MenuItems = menuItemsSourceList; + AutoSuggestBox.ItemsSource = _autoSuggestBoxItems; + AutoSuggestBox.SuggestionChosen += AutoSuggestBoxOnSuggestionChosen; } - if (FooterMenuItems?.Count > 0) - OnFooterMenuItemsChanged(); + InvalidateArrange(); + InvalidateVisual(); + UpdateLayout(); UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); } @@ -92,7 +85,14 @@ private void OnLoaded(object sender, RoutedEventArgs e) /// protected virtual void OnUnloaded(object sender, RoutedEventArgs e) { + Loaded -= OnLoaded; + Unloaded -= OnUnloaded; + SizeChanged -= OnSizeChanged; + NavigationViewContentPresenter.Navigated -= OnNavigationViewContentPresenterNavigated; + + if (AutoSuggestBox is not null) + AutoSuggestBox.SuggestionChosen -= AutoSuggestBoxOnSuggestionChosen; } /// @@ -106,19 +106,14 @@ protected virtual void OnSizeChanged(object sender, SizeChangedEventArgs e) /// /// This virtual method is called when is clicked. /// - protected virtual void OnBackButtonClick(object sender, RoutedEventArgs e) - { - GoBack(); - } + protected virtual void OnBackButtonClick(object sender, RoutedEventArgs e) => GoBack(); /// /// This virtual method is called when is clicked. /// protected virtual void OnToggleButtonClick(object sender, RoutedEventArgs e) { -#if DEBUG - System.Diagnostics.Debug.WriteLine("Toggle"); -#endif + Debug.WriteLine("Toggle"); } /// @@ -131,7 +126,6 @@ protected virtual void OnMenuItemsChanged() UpdateLayout(); UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); } @@ -141,7 +135,6 @@ protected virtual void OnMenuItemsChanged() protected virtual void OnFooterMenuItemsChanged() { UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); } @@ -164,7 +157,8 @@ protected virtual void OnPaneDisplayModeChanged() /// protected virtual void OnItemTemplateChanged() { - UpdateMenuItemsTemplate(); + UpdateMenuItemsTemplate(MenuItems); + UpdateMenuItemsTemplate(FooterMenuItems); } internal void ToggleAllExpands() @@ -179,121 +173,109 @@ internal void OnNavigationViewItemClick(NavigationViewItem navigationViewItem) NavigateInternal(navigationViewItem, null, true, false); } - private void UpdateMenuItemsTemplate() - { - if (MenuItems is IEnumerable enumerableItemsSource) - foreach (var singleMenuItem in enumerableItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - if (ItemTemplate != null && singleNavigationViewItem.Template != ItemTemplate) - singleNavigationViewItem.Template = ItemTemplate; - - if (FooterMenuItems is IEnumerable enumerableFooterItemsSource) - foreach (var singleMenuItem in enumerableFooterItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - if (ItemTemplate != null && singleNavigationViewItem.Template != ItemTemplate) - singleNavigationViewItem.Template = ItemTemplate; - } - - private void UpdateAutoSuggestBoxSuggestions() + protected void UpdateAutoSuggestBoxSuggestions() { if (AutoSuggestBox == null) return; - _autoSuggestBoxItems = new ObservableCollection(); - - if (MenuItems is IEnumerable enumerableItemsSource) - foreach (var singleMenuItem in enumerableItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.Content is string content && singleNavigationViewItem.TargetPageType != null && !String.IsNullOrWhiteSpace(content)) - _autoSuggestBoxItems.Add(content); - - if (singleNavigationViewItem.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem { Content: string subContent, TargetPageType: not null } && !String.IsNullOrWhiteSpace(subContent)) - _autoSuggestBoxItems.Add(subContent); - } - - if (FooterMenuItems is IEnumerable enumerableFooterItemsSource) - foreach (var singleMenuItem in enumerableFooterItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.Content is string content && singleNavigationViewItem.TargetPageType != null && !String.IsNullOrWhiteSpace(content)) - _autoSuggestBoxItems.Add(content); - - if (singleNavigationViewItem.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem { Content: string subContent, TargetPageType: not null } && !String.IsNullOrWhiteSpace(subContent)) - _autoSuggestBoxItems.Add(subContent); - } - - AutoSuggestBox.ItemsSource = _autoSuggestBoxItems; - - AutoSuggestBox.SuggestionChosen -= AutoSuggestBoxOnSuggestionChosen; - AutoSuggestBox.SuggestionChosen += AutoSuggestBoxOnSuggestionChosen; + _autoSuggestBoxItems.Clear(); + + AddItemsToAutoSuggestBoxItemsForMenuItems(MenuItems); + AddItemsToAutoSuggestBoxItemsForMenuItems(FooterMenuItems); } /// /// Navigate to the page after its name is selected in . /// - private void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e) + protected void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e) + { + if (sender is not AutoSuggestBox { ChosenSuggestion: string selectedSuggestBoxItem }) + return; + + if (string.IsNullOrEmpty(selectedSuggestBoxItem)) + return; + + if (NavigateToMenuItemFromAutoSuggestBox(MenuItems, selectedSuggestBoxItem)) + return; + + NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, selectedSuggestBoxItem); + } + + private void AddItemsToAutoSuggestBoxItemsForMenuItems(IList? list) { - if (sender is not Controls.AutoSuggestBox autoSuggestBox) + if (list is null) return; - var selectedSuggestBoxItem = autoSuggestBox.ChosenSuggestion?.ToString() ?? String.Empty; + foreach (var singleMenuItem in list) + { + if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) + continue; + + if (singleNavigationViewItem is { Content: string content, TargetPageType: { } } && !string.IsNullOrWhiteSpace(content)) + _autoSuggestBoxItems.Add(content); + + if (!(singleNavigationViewItem.MenuItems?.Count > 0)) + continue; + + foreach (var subMenuItem in singleNavigationViewItem.MenuItems) + { + if (subMenuItem is NavigationViewItem { Content: string subContent, TargetPageType: not null } && !string.IsNullOrWhiteSpace(subContent)) + _autoSuggestBoxItems.Add(subContent); + } + + } + } + + private bool NavigateToMenuItemFromAutoSuggestBox(IList? list, string selectedSuggestBoxItem) + { + if (list is null) + return false; + + foreach (var singleMenuItem in list) + { + if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) + continue; + + if (singleNavigationViewItem.Content is string content && content == selectedSuggestBoxItem) + { + NavigateInternal(singleNavigationViewItem, null, true, false); + singleNavigationViewItem.BringIntoView(); + singleNavigationViewItem.Focus(); - if (selectedSuggestBoxItem == String.Empty) + return true; + } + + if (!(singleNavigationViewItem.MenuItems?.Count > 0)) + continue; + + foreach (var subMenuItem in singleNavigationViewItem.MenuItems) + { + if (subMenuItem is not NavigationViewItem { Content: string subContent } subMenuNavigationViewItem || subContent != selectedSuggestBoxItem) + continue; + + NavigateInternal(subMenuNavigationViewItem, null, true, false); + subMenuNavigationViewItem.BringIntoView(); + subMenuNavigationViewItem.Focus(); + + return true; + } + } + + return false; + } + + private void UpdateMenuItemsTemplate(IList? list) + { + if (list is null) return; - if (MenuItems is IEnumerable enumerableItemsSource) - foreach (var singleMenuItem in enumerableItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.Content is string content && content == selectedSuggestBoxItem) - { - NavigateInternal(singleNavigationViewItem, null, true, false); - singleNavigationViewItem.BringIntoView(); - singleNavigationViewItem.Focus(); - - return; - } - - if (singleNavigationViewItem.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem { Content: string subContent } subMenuNavigationViewItem && subContent == selectedSuggestBoxItem) - { - NavigateInternal(subMenuNavigationViewItem, null, true, false); - subMenuNavigationViewItem.BringIntoView(); - subMenuNavigationViewItem.Focus(); - - return; - } - } - - if (FooterMenuItems is IEnumerable enumerableFooterItemsSource) - foreach (var singleMenuItem in enumerableFooterItemsSource) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.Content is string content && content == selectedSuggestBoxItem) - { - NavigateInternal(singleNavigationViewItem, null, true, false); - singleNavigationViewItem.BringIntoView(); - singleNavigationViewItem.Focus(); - - return; - } - - if (singleNavigationViewItem.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem { Content: string subContent } subMenuNavigationViewItem && subContent == selectedSuggestBoxItem) - { - NavigateInternal(subMenuNavigationViewItem, null, true, false); - subMenuNavigationViewItem.BringIntoView(); - subMenuNavigationViewItem.Focus(); - - return; - } - } + foreach (var singleMenuItem in list) + { + if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) + continue; + + if (ItemTemplate is not null && singleNavigationViewItem.Template != ItemTemplate) + singleNavigationViewItem.Template = ItemTemplate; + } } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs index e72c3ae0a..7ecd95a06 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs @@ -345,7 +345,7 @@ public TransitionType TransitionType private static void OnMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { - if (d is not NavigationView navigationView) + if (d is not NavigationView { IsInitialized: true } navigationView) return; navigationView.OnMenuItemsChanged(); @@ -361,7 +361,7 @@ private static void OnMenuItemsSourcePropertyChanged(DependencyObject? d, Depend private static void OnFooterMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { - if (d is not NavigationView navigationView) + if (d is not NavigationView { IsInitialized: true } navigationView) return; navigationView.OnFooterMenuItemsChanged(); From b42807fdbc0b078b0e14a8f2ae41a68152704a3f Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 20:05:44 +0600 Subject: [PATCH 03/27] added BreadcrumbBar support --- .../Views/Windows/MainWindow.xaml | 5 +- .../Navigation/INavigationViewItem.cs | 5 + .../Navigation/NavigationView.Base.cs | 30 ++++-- .../Navigation/NavigationViewBreadcrumb.cs | 99 ------------------- .../NavigationViewBreadcrumbItem.cs | 13 +++ src/Wpf.Ui/Styles/Controls/BreadcrumbBar.xaml | 2 +- .../Controls/NavigationViewBreadcrumb.xaml | 42 -------- .../NavigationViewBreadcrumbItem.xaml | 17 ++++ src/Wpf.Ui/Styles/Wpf.Ui.xaml | 2 +- 9 files changed, 59 insertions(+), 156 deletions(-) delete mode 100644 src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumb.cs create mode 100644 src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumbItem.cs delete mode 100644 src/Wpf.Ui/Styles/Controls/NavigationViewBreadcrumb.xaml create mode 100644 src/Wpf.Ui/Styles/Controls/NavigationViewBreadcrumbItem.xaml diff --git a/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml b/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml index df1b99c8d..d95ac0e18 100644 --- a/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml +++ b/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml @@ -35,10 +35,7 @@ PaneDisplayMode="Left" SelectionChanged="OnNavigationSelectionChanged"> - + public interface INavigationViewItem { + /// + /// Get or sets content + /// + object Content { get; } + /// /// Unique identifier that allows the item to be located in the navigation. /// diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index 7a68cb487..168c9505d 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -9,10 +9,10 @@ using System; using System.Collections; using System.Collections.ObjectModel; -using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Windows; +using Wpf.Ui.Common; namespace Wpf.Ui.Controls.Navigation; @@ -25,7 +25,8 @@ namespace Wpf.Ui.Controls.Navigation; [System.Drawing.ToolboxBitmap(typeof(NavigationView), "NavigationView.bmp")] public partial class NavigationView : System.Windows.Controls.Control, INavigationView { - private ObservableCollection _autoSuggestBoxItems = new(); + private readonly ObservableCollection _autoSuggestBoxItems = new(); + private readonly ObservableCollection _breadcrumbBarItems = new(); /// public INavigationViewItem? SelectedItem { get; private set; } @@ -42,11 +43,8 @@ public NavigationView() { NavigationParent = this; - SetValue(MenuItemsProperty, - new ObservableCollection()); - - SetValue(FooterMenuItemsProperty, - new ObservableCollection()); + SetValue(MenuItemsProperty, new ObservableCollection()); + SetValue(FooterMenuItemsProperty, new ObservableCollection()); Loaded += OnLoaded; Unloaded += OnUnloaded; @@ -58,8 +56,12 @@ protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); - if (Header is NavigationViewBreadcrumb navigationViewBreadcrumb) - navigationViewBreadcrumb.NavigationView = this; + if (Header is BreadcrumbBar breadcrumbBar) + { + breadcrumbBar.ItemsSource = _breadcrumbBarItems; + breadcrumbBar.ItemTemplate ??= Application.Current.TryFindResource("NavigationViewItemDataTemplate") as DataTemplate; + breadcrumbBar.ItemClicked += BreadcrumbBarOnItemClicked; + } if (AutoSuggestBox is not null) { @@ -93,6 +95,11 @@ protected virtual void OnUnloaded(object sender, RoutedEventArgs e) if (AutoSuggestBox is not null) AutoSuggestBox.SuggestionChosen -= AutoSuggestBoxOnSuggestionChosen; + + if (Header is BreadcrumbBar breadcrumbBar) + { + breadcrumbBar.ItemClicked -= BreadcrumbBarOnItemClicked; + } } /// @@ -173,6 +180,11 @@ internal void OnNavigationViewItemClick(NavigationViewItem navigationViewItem) NavigateInternal(navigationViewItem, null, true, false); } + protected virtual void BreadcrumbBarOnItemClicked(BreadcrumbBar sender, BreadcrumbBarItemClickedEventArgs e) + { + + } + protected void UpdateAutoSuggestBoxSuggestions() { if (AutoSuggestBox == null) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumb.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumb.cs deleted file mode 100644 index aacdc183e..000000000 --- a/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumb.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. - -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. -// Copyright (C) Leszek Pomianowski and WPF UI Contributors. -// All Rights Reserved. - - -using System; -using System.Windows; - -namespace Wpf.Ui.Controls.Navigation; - -/// -/// Breadcrumb control allows you to keep track and maintain awareness of your locations within . -/// -public class NavigationViewBreadcrumb : System.Windows.Controls.Control -{ - /// - /// Property for . - /// - public static readonly DependencyProperty NavigationViewProperty = DependencyProperty.Register(nameof(NavigationView), - typeof(INavigationView), typeof(NavigationViewBreadcrumb), - new PropertyMetadata(((NavigationViewBreadcrumb)null!), OnNavigationViewPropertyChanged)); - - /// - /// Property for . - /// - public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), - typeof(string), typeof(NavigationViewBreadcrumb), - new PropertyMetadata(String.Empty)); - - - /// - /// Pinned navigation control. - /// - public INavigationView NavigationView - { - get => (INavigationView)GetValue(NavigationViewProperty); - set => SetValue(NavigationViewProperty, value); - } - - /// - /// Primary breadcrumb navigation element. - /// - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - - public NavigationViewBreadcrumb() - { - if (NavigationView != null) - UpdateRenderedItems(); - } - - /// - /// This virtual method is called when the is changed. - /// - protected virtual void OnNavigationViewChanged() - { - if (NavigationView == null) - return; - - NavigationView.SelectionChanged -= OnNavigationViewSelectionChanged; - NavigationView.SelectionChanged += OnNavigationViewSelectionChanged; - } - - /// - /// This virtual method is called when the of the is changed. - /// - protected virtual void OnNavigationViewSelectionChanged(object sender, RoutedEventArgs e) - { - UpdateRenderedItems(); - } - - private static void OnNavigationViewPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is not NavigationViewBreadcrumb breadcrumb) - return; - - breadcrumb.OnNavigationViewChanged(); - } - - private void UpdateRenderedItems() - { - if (NavigationView.SelectedItem is not NavigationViewItem navigationViewItem) - { - Text = String.Empty; - - return; - } - - // TODO: Multilevel - Text = navigationViewItem.Content?.ToString() ?? String.Empty; - } -} diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumbItem.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumbItem.cs new file mode 100644 index 000000000..96fbd38f2 --- /dev/null +++ b/src/Wpf.Ui/Controls/Navigation/NavigationViewBreadcrumbItem.cs @@ -0,0 +1,13 @@ +namespace Wpf.Ui.Controls.Navigation; + +internal class NavigationViewBreadcrumbItem +{ + public NavigationViewBreadcrumbItem(INavigationViewItem item) + { + Content = item.Content; + PageId = item.Id; + } + + public object Content { get; } + public object PageId { get; } +} diff --git a/src/Wpf.Ui/Styles/Controls/BreadcrumbBar.xaml b/src/Wpf.Ui/Styles/Controls/BreadcrumbBar.xaml index 2d26c1cf0..ecabfe128 100644 --- a/src/Wpf.Ui/Styles/Controls/BreadcrumbBar.xaml +++ b/src/Wpf.Ui/Styles/Controls/BreadcrumbBar.xaml @@ -13,7 +13,7 @@ - - \ No newline at end of file diff --git a/src/Wpf.Ui/Styles/Controls/NavigationViewBreadcrumbItem.xaml b/src/Wpf.Ui/Styles/Controls/NavigationViewBreadcrumbItem.xaml new file mode 100644 index 000000000..f483140d6 --- /dev/null +++ b/src/Wpf.Ui/Styles/Controls/NavigationViewBreadcrumbItem.xaml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Wpf.Ui/Styles/Wpf.Ui.xaml b/src/Wpf.Ui/Styles/Wpf.Ui.xaml index 86d1b702c..956245665 100644 --- a/src/Wpf.Ui/Styles/Wpf.Ui.xaml +++ b/src/Wpf.Ui/Styles/Wpf.Ui.xaml @@ -53,7 +53,7 @@ - + From da11d1e76994c89e8728dfedba44236148045957 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 20:50:25 +0600 Subject: [PATCH 04/27] added dictionaries PageTagNavigationViewsDictionary , PageIdNavigationViewsDictionary , PageTypeNavigationViewsDictionary --- .../Navigation/NavigationView.Base.cs | 58 +++++++++++++------ .../Navigation/NavigationView.Navigation.cs | 19 ++---- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index 168c9505d..8a4630d9d 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -8,6 +8,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; @@ -28,6 +29,10 @@ public partial class NavigationView : System.Windows.Controls.Control, INavigati private readonly ObservableCollection _autoSuggestBoxItems = new(); private readonly ObservableCollection _breadcrumbBarItems = new(); + protected Dictionary PageTagNavigationViewsDictionary = new(); + protected Dictionary PageIdNavigationViewsDictionary = new(); + protected Dictionary PageTypeNavigationViewsDictionary = new(); + /// public INavigationViewItem? SelectedItem { get; private set; } @@ -75,6 +80,9 @@ protected override void OnInitialized(EventArgs e) UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); + + AddItemsToDictionariesFromMenuItems(MenuItems); + AddItemsToDictionariesFromMenuItems(FooterMenuItems); } private void OnLoaded(object sender, RoutedEventArgs e) @@ -134,6 +142,8 @@ protected virtual void OnMenuItemsChanged() UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); + + AddItemsToDictionariesFromMenuItems(MenuItems); } /// @@ -143,6 +153,8 @@ protected virtual void OnFooterMenuItemsChanged() { UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); + + AddItemsToDictionariesFromMenuItems(FooterMenuItems); } /// @@ -213,6 +225,33 @@ protected void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, selectedSuggestBoxItem); } + protected void AddItemsToDictionariesFromMenuItems(IList? list) + { + if (list is null) + return; + + foreach (var singleMenuItem in list) + { + if (singleMenuItem is not INavigationViewItem singleNavigationViewItem) + continue; + + if (!PageIdNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.Id)) + PageIdNavigationViewsDictionary.Add(singleNavigationViewItem.Id, singleNavigationViewItem); + + if (!PageTagNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageTag)) + PageTagNavigationViewsDictionary.Add(singleNavigationViewItem.TargetPageTag, singleNavigationViewItem); + + if (singleNavigationViewItem.TargetPageType is not null && !PageTypeNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageType)) + PageTypeNavigationViewsDictionary.Add(singleNavigationViewItem.TargetPageType, singleNavigationViewItem); + + + if (!(singleNavigationViewItem.MenuItems?.Count > 0)) + continue; + + AddItemsToDictionariesFromMenuItems(singleNavigationViewItem.MenuItems); + } + } + private void AddItemsToAutoSuggestBoxItemsForMenuItems(IList? list) { if (list is null) @@ -229,12 +268,7 @@ private void AddItemsToAutoSuggestBoxItemsForMenuItems(IList? list) if (!(singleNavigationViewItem.MenuItems?.Count > 0)) continue; - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - { - if (subMenuItem is NavigationViewItem { Content: string subContent, TargetPageType: not null } && !string.IsNullOrWhiteSpace(subContent)) - _autoSuggestBoxItems.Add(subContent); - } - + AddItemsToAutoSuggestBoxItemsForMenuItems(singleNavigationViewItem.MenuItems); } } @@ -260,17 +294,7 @@ private bool NavigateToMenuItemFromAutoSuggestBox(IList? list, string selectedSu if (!(singleNavigationViewItem.MenuItems?.Count > 0)) continue; - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - { - if (subMenuItem is not NavigationViewItem { Content: string subContent } subMenuNavigationViewItem || subContent != selectedSuggestBoxItem) - continue; - - NavigateInternal(subMenuNavigationViewItem, null, true, false); - subMenuNavigationViewItem.BringIntoView(); - subMenuNavigationViewItem.Focus(); - - return true; - } + NavigateToMenuItemFromAutoSuggestBox(singleNavigationViewItem.MenuItems, selectedSuggestBoxItem); } return false; diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index c4bf5b936..a015d6f92 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -20,12 +20,11 @@ namespace Wpf.Ui.Controls.Navigation; public partial class NavigationView { - private IServiceProvider? _serviceProvider = null; - - private IPageService? _pageService = null; - private readonly List _journal = new(); + private IServiceProvider? _serviceProvider; + private IPageService? _pageService; + private int _currentIndexInJournal = 0; /// @@ -41,11 +40,7 @@ public void SetServiceProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; /// - public bool Navigate(Type pageType) - => Navigate(pageType, null!); - - /// - public bool Navigate(Type pageType, object dataContext) + public bool Navigate(Type pageType, object? dataContext = null) { if (MenuItems is IEnumerable enumerableMenuItems) foreach (var singleMenuItem in enumerableMenuItems) @@ -79,11 +74,7 @@ public bool Navigate(Type pageType, object dataContext) } /// - public bool Navigate(string pageIdOrTargetTag) - => Navigate(pageIdOrTargetTag, null!); - - /// - public bool Navigate(string pageIdOrTargetTag, object dataContext) + public bool Navigate(string pageIdOrTargetTag, object? dataContext = null) { if (MenuItems is IEnumerable enumerableMenuItems) foreach (var singleMenuItem in enumerableMenuItems) From da992b5b454e45617cfd5fc98fffdf20723b35ff Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 20:57:58 +0600 Subject: [PATCH 05/27] start using NavigationViewsDictionary dictionaries --- .../Navigation/NavigationView.Base.cs | 11 ++--- .../Navigation/NavigationView.Navigation.cs | 47 +++---------------- 2 files changed, 11 insertions(+), 47 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index 8a4630d9d..0954572e4 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -29,8 +29,7 @@ public partial class NavigationView : System.Windows.Controls.Control, INavigati private readonly ObservableCollection _autoSuggestBoxItems = new(); private readonly ObservableCollection _breadcrumbBarItems = new(); - protected Dictionary PageTagNavigationViewsDictionary = new(); - protected Dictionary PageIdNavigationViewsDictionary = new(); + protected Dictionary PageIdOrTargetTagNavigationViewsDictionary = new(); protected Dictionary PageTypeNavigationViewsDictionary = new(); /// @@ -235,11 +234,11 @@ protected void AddItemsToDictionariesFromMenuItems(IList? list) if (singleMenuItem is not INavigationViewItem singleNavigationViewItem) continue; - if (!PageIdNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.Id)) - PageIdNavigationViewsDictionary.Add(singleNavigationViewItem.Id, singleNavigationViewItem); + if (!PageIdOrTargetTagNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.Id)) + PageIdOrTargetTagNavigationViewsDictionary.Add(singleNavigationViewItem.Id, singleNavigationViewItem); - if (!PageTagNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageTag)) - PageTagNavigationViewsDictionary.Add(singleNavigationViewItem.TargetPageTag, singleNavigationViewItem); + if (!PageIdOrTargetTagNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageTag)) + PageIdOrTargetTagNavigationViewsDictionary.Add(singleNavigationViewItem.TargetPageTag, singleNavigationViewItem); if (singleNavigationViewItem.TargetPageType is not null && !PageTypeNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageType)) PageTypeNavigationViewsDictionary.Add(singleNavigationViewItem.TargetPageType, singleNavigationViewItem); diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index a015d6f92..850d242bb 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -42,54 +42,19 @@ public void SetServiceProvider(IServiceProvider serviceProvider) /// public bool Navigate(Type pageType, object? dataContext = null) { - if (MenuItems is IEnumerable enumerableMenuItems) - foreach (var singleMenuItem in enumerableMenuItems) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.TargetPageType != null && singleNavigationViewItem.TargetPageType == pageType) - return NavigateInternal(singleNavigationViewItem, dataContext, true, true); ; - - if (singleNavigationViewItem?.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem subMenuNavigationViewItem) - if (subMenuNavigationViewItem.TargetPageType != null && subMenuNavigationViewItem.TargetPageType == pageType) - return NavigateInternal(subMenuNavigationViewItem, dataContext, true, true); - } - - if (FooterMenuItems is IEnumerable enumerableFooterMenuItems) - foreach (var singleMenuItem in enumerableFooterMenuItems) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - { - if (singleNavigationViewItem.TargetPageType != null && singleNavigationViewItem.TargetPageType == pageType) - return NavigateInternal(singleNavigationViewItem, dataContext, true, true); - - if (singleNavigationViewItem?.MenuItems?.Count > 0) - foreach (var subMenuItem in singleNavigationViewItem.MenuItems) - if (subMenuItem is NavigationViewItem subMenuNavigationViewItem) - if (subMenuNavigationViewItem.TargetPageType != null && subMenuNavigationViewItem.TargetPageType == pageType) - return NavigateInternal(subMenuNavigationViewItem, dataContext, true, true); - } + if (!PageTypeNavigationViewsDictionary.TryGetValue(pageType, out var navigationViewItem)) + return false; - return false; + return NavigateInternal(navigationViewItem, dataContext, true, true); } /// public bool Navigate(string pageIdOrTargetTag, object? dataContext = null) { - if (MenuItems is IEnumerable enumerableMenuItems) - foreach (var singleMenuItem in enumerableMenuItems) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - if (singleNavigationViewItem.Id == pageIdOrTargetTag || singleNavigationViewItem?.TargetPageTag == pageIdOrTargetTag) - return NavigateInternal(singleNavigationViewItem, dataContext, true, true); - - if (FooterMenuItems is IEnumerable enumerableFooterMenuItems) - foreach (var singleMenuItem in enumerableFooterMenuItems) - if (singleMenuItem is NavigationViewItem singleNavigationViewItem) - if (singleNavigationViewItem.Id == pageIdOrTargetTag || - singleNavigationViewItem?.TargetPageTag == pageIdOrTargetTag) - return NavigateInternal(singleNavigationViewItem, dataContext, true, true); + if (!PageIdOrTargetTagNavigationViewsDictionary.TryGetValue(pageIdOrTargetTag, out var navigationViewItem)) + return false; - return false; + return NavigateInternal(navigationViewItem, dataContext, true, true); } /// From 55ce6bb24f21c7652d0a4ce4d0bc6a54679ae2b3 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Wed, 25 Jan 2023 21:38:13 +0600 Subject: [PATCH 06/27] moved navigation aware login to the NavigationViewContentPresenter --- .../Navigation/NavigationView.Base.cs | 2 - .../Navigation/NavigationView.Navigation.cs | 62 +-------------- .../NavigationView.TemplateParts.cs | 1 - .../NavigationViewContentPresenter.cs | 76 +++++++++++++++++++ .../Styles/Controls/NavigationView.xaml | 8 +- 5 files changed, 85 insertions(+), 64 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index 0954572e4..e701e1c97 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -98,8 +98,6 @@ protected virtual void OnUnloaded(object sender, RoutedEventArgs e) Unloaded -= OnUnloaded; SizeChanged -= OnSizeChanged; - NavigationViewContentPresenter.Navigated -= OnNavigationViewContentPresenterNavigated; - if (AutoSuggestBox is not null) AutoSuggestBox.SuggestionChosen -= AutoSuggestBoxOnSuggestionChosen; diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index 850d242bb..cabe44f43 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -6,14 +6,11 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -#nullable enable - using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Windows; -using System.Windows.Navigation; -using Wpf.Ui.Animations; using Wpf.Ui.Contracts; namespace Wpf.Ui.Controls.Navigation; @@ -136,9 +133,7 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, IsBackEnabled = _journal.Count > 0; -#if DEBUG - System.Diagnostics.Debug.WriteLine($"DEBUG | {viewItem.Id} - {viewItem.TargetPageTag ?? "NO_TAG"} | NAVIGATED"); -#endif + Debug.WriteLine($"DEBUG | {viewItem.Id} - {viewItem.TargetPageTag ?? "NO_TAG"} | NAVIGATED"); RenderSelectedItemContent(viewItem, dataContext); @@ -223,61 +218,10 @@ private void RenderSelectedItemContent(INavigationViewItem viewItem, object? dat private void UpdateContent(object? content, object? dataContext) { - if (NavigationViewContentPresenter == null) - return; - - NotifyContentAboutNavigatingFrom(NavigationViewContentPresenter?.Content ?? null); - if (dataContext != null && content is FrameworkElement frameworkViewContent) frameworkViewContent.DataContext = dataContext; - NavigationViewContentPresenter!.Navigate(content); - } - - protected virtual void OnNavigationViewContentPresenterNavigated(object sender, NavigationEventArgs e) - { - if (sender is not NavigationViewContentPresenter contentPresenter) - return; - - NotifyContentAboutNavigatingTo(contentPresenter?.Content ?? null); - - if (contentPresenter != null) - ApplyTransitionEffectToNavigatedPage(contentPresenter); - } - - private void NotifyContentAboutNavigatingFrom(object? content) - { - if (content is INavigationAware navigationAwareNavigationContent) - navigationAwareNavigationContent.OnNavigatedFrom(); - - if (content is INavigableView navigableView && navigableView.ViewModel is INavigationAware navigationAwareNavigableViewViewModel) - navigationAwareNavigableViewViewModel.OnNavigatedFrom(); - - if (content is FrameworkElement { DataContext: INavigationAware navigationAwareCurrentContent }) - navigationAwareCurrentContent.OnNavigatedFrom(); - } - - private void NotifyContentAboutNavigatingTo(object? content) - { - if (content is INavigationAware navigationAwareNavigationContent) - navigationAwareNavigationContent.OnNavigatedTo(); - - if (content is INavigableView navigableView && navigableView.ViewModel is INavigationAware navigationAwareNavigableViewViewModel) - navigationAwareNavigableViewViewModel.OnNavigatedTo(); - - if (content is FrameworkElement { DataContext: INavigationAware navigationAwareCurrentContent }) - navigationAwareCurrentContent.OnNavigatedTo(); - } - - private void ApplyTransitionEffectToNavigatedPage(NavigationViewContentPresenter contentPresenter) - { - if (TransitionDuration < 1) - return; - - if (contentPresenter.Content == null) - return; - - Transitions.ApplyTransition(contentPresenter.Content, TransitionType, TransitionDuration); + NavigationViewContentPresenter.Navigate(content); } private void UpdateSelectionForMenuItems() diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs index 282ad79b3..5ae6c5f2e 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.TemplateParts.cs @@ -77,7 +77,6 @@ public override void OnApplyTemplate() MenuItemsItemsControl = GetTemplateChild(TemplateElementMenuItemsItemsControl); FooterMenuItemsItemsControl = GetTemplateChild(TemplateElementFooterMenuItemsItemsControl); - NavigationViewContentPresenter.Navigated += OnNavigationViewContentPresenterNavigated; MenuItemsItemsControl.ItemsSource = MenuItems; FooterMenuItemsItemsControl.ItemsSource = FooterMenuItems; diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewContentPresenter.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewContentPresenter.cs index 3fd80966c..47578afa5 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationViewContentPresenter.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationViewContentPresenter.cs @@ -6,14 +6,47 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. +using System; +using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; +using Wpf.Ui.Animations; namespace Wpf.Ui.Controls.Navigation; public class NavigationViewContentPresenter : Frame { + /// + /// Property for . + /// + public static readonly DependencyProperty TransitionDurationProperty = + DependencyProperty.Register(nameof(TransitionDuration), typeof(int), typeof(NavigationViewContentPresenter), + new FrameworkPropertyMetadata(200)); + + /// + /// Property for . + /// + public static readonly DependencyProperty TransitionTypeProperty = + DependencyProperty.Register(nameof(TransitionType), typeof(TransitionType), + typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(TransitionType.FadeInWithSlide)); + + [Bindable(true), Category("Appearance")] + public int TransitionDuration + { + get => (int)GetValue(TransitionDurationProperty); + set => SetValue(TransitionDurationProperty, value); + } + + /// + /// Gets or sets type of transitions during navigation. + /// + public TransitionType TransitionType + { + get => (TransitionType)GetValue(TransitionTypeProperty); + set => SetValue(TransitionTypeProperty, value); + } + static NavigationViewContentPresenter() { DefaultStyleKeyProperty.OverrideMetadata( @@ -32,4 +65,47 @@ static NavigationViewContentPresenter() typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(JournalOwnership.UsesParentJournal)); } + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + Navigating += static (_, eventArgs) => + { + if (eventArgs.Content is null) + return; + + NotifyContentAboutNavigatingTo(eventArgs.Content); + }; + + Navigated += (sender, eventArgs) => + { + var self = (NavigationViewContentPresenter)sender; + + if (eventArgs.Content is null) + return; + + self.ApplyTransitionEffectToNavigatedPage(eventArgs.Content); + }; + } + + private static void NotifyContentAboutNavigatingTo(object content) + { + if (content is INavigationAware navigationAwareNavigationContent) + navigationAwareNavigationContent.OnNavigatedTo(); + + if (content is INavigableView { ViewModel: INavigationAware navigationAwareNavigableViewViewModel }) + navigationAwareNavigableViewViewModel.OnNavigatedTo(); + + if (content is FrameworkElement { DataContext: INavigationAware navigationAwareCurrentContent }) + navigationAwareCurrentContent.OnNavigatedTo(); + } + + private void ApplyTransitionEffectToNavigatedPage(object content) + { + if (TransitionDuration < 1) + return; + + Transitions.ApplyTransition(content, TransitionType, TransitionDuration); + } } diff --git a/src/Wpf.Ui/Styles/Controls/NavigationView.xaml b/src/Wpf.Ui/Styles/Controls/NavigationView.xaml index e7c297f38..fe2fadf23 100644 --- a/src/Wpf.Ui/Styles/Controls/NavigationView.xaml +++ b/src/Wpf.Ui/Styles/Controls/NavigationView.xaml @@ -621,7 +621,9 @@ + Margin="{TemplateBinding Padding}" + TransitionDuration="{TemplateBinding TransitionDuration}" + TransitionType="{TemplateBinding TransitionType}" /> + Margin="{TemplateBinding Padding}" + TransitionDuration="{TemplateBinding TransitionDuration}" + TransitionType="{TemplateBinding TransitionType}" /> Date: Wed, 25 Jan 2023 21:57:03 +0600 Subject: [PATCH 07/27] removed duplicate code --- .../Navigation/NavigationView.Base.cs | 97 +++++++++++++--- .../Navigation/NavigationView.Navigation.cs | 107 ++---------------- .../Navigation/NavigationViewActivator.cs | 14 +-- 3 files changed, 94 insertions(+), 124 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index e701e1c97..e5dba3100 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -80,8 +80,7 @@ protected override void OnInitialized(EventArgs e) UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); - AddItemsToDictionariesFromMenuItems(MenuItems); - AddItemsToDictionariesFromMenuItems(FooterMenuItems); + AddItemsToDictionaries(); } private void OnLoaded(object sender, RoutedEventArgs e) @@ -140,7 +139,7 @@ protected virtual void OnMenuItemsChanged() UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); - AddItemsToDictionariesFromMenuItems(MenuItems); + AddItemsToDictionaries(MenuItems); } /// @@ -151,7 +150,7 @@ protected virtual void OnFooterMenuItemsChanged() UpdateAutoSuggestBoxSuggestions(); UpdateSelectionForMenuItems(); - AddItemsToDictionariesFromMenuItems(FooterMenuItems); + AddItemsToDictionaries(FooterMenuItems); } /// @@ -173,8 +172,7 @@ protected virtual void OnPaneDisplayModeChanged() /// protected virtual void OnItemTemplateChanged() { - UpdateMenuItemsTemplate(MenuItems); - UpdateMenuItemsTemplate(FooterMenuItems); + UpdateMenuItemsTemplate(); } internal void ToggleAllExpands() @@ -194,21 +192,20 @@ protected virtual void BreadcrumbBarOnItemClicked(BreadcrumbBar sender, Breadcru } - protected void UpdateAutoSuggestBoxSuggestions() + private void UpdateAutoSuggestBoxSuggestions() { if (AutoSuggestBox == null) return; _autoSuggestBoxItems.Clear(); - AddItemsToAutoSuggestBoxItemsForMenuItems(MenuItems); - AddItemsToAutoSuggestBoxItemsForMenuItems(FooterMenuItems); + AddItemsToAutoSuggestBoxItems(); } /// /// Navigate to the page after its name is selected in . /// - protected void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e) + private void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e) { if (sender is not AutoSuggestBox { ChosenSuggestion: string selectedSuggestBoxItem }) return; @@ -222,7 +219,7 @@ protected void AutoSuggestBoxOnSuggestionChosen(object sender, RoutedEventArgs e NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, selectedSuggestBoxItem); } - protected void AddItemsToDictionariesFromMenuItems(IList? list) + protected virtual void AddItemsToDictionaries(IList? list) { if (list is null) return; @@ -245,11 +242,17 @@ protected void AddItemsToDictionariesFromMenuItems(IList? list) if (!(singleNavigationViewItem.MenuItems?.Count > 0)) continue; - AddItemsToDictionariesFromMenuItems(singleNavigationViewItem.MenuItems); + AddItemsToDictionaries(singleNavigationViewItem.MenuItems); } } - private void AddItemsToAutoSuggestBoxItemsForMenuItems(IList? list) + protected virtual void AddItemsToDictionaries() + { + AddItemsToDictionaries(MenuItems); + AddItemsToDictionaries(FooterMenuItems); + } + + protected virtual void AddItemsToAutoSuggestBoxItems(IList? list) { if (list is null) return; @@ -265,11 +268,17 @@ private void AddItemsToAutoSuggestBoxItemsForMenuItems(IList? list) if (!(singleNavigationViewItem.MenuItems?.Count > 0)) continue; - AddItemsToAutoSuggestBoxItemsForMenuItems(singleNavigationViewItem.MenuItems); + AddItemsToAutoSuggestBoxItems(singleNavigationViewItem.MenuItems); } } - private bool NavigateToMenuItemFromAutoSuggestBox(IList? list, string selectedSuggestBoxItem) + protected virtual void AddItemsToAutoSuggestBoxItems() + { + AddItemsToAutoSuggestBoxItems(MenuItems); + AddItemsToAutoSuggestBoxItems(FooterMenuItems); + } + + protected virtual bool NavigateToMenuItemFromAutoSuggestBox(IList? list, string selectedSuggestBoxItem) { if (list is null) return false; @@ -297,7 +306,7 @@ private bool NavigateToMenuItemFromAutoSuggestBox(IList? list, string selectedSu return false; } - private void UpdateMenuItemsTemplate(IList? list) + protected virtual void UpdateMenuItemsTemplate(IList? list) { if (list is null) return; @@ -311,4 +320,60 @@ private void UpdateMenuItemsTemplate(IList? list) singleNavigationViewItem.Template = ItemTemplate; } } + + protected virtual void UpdateMenuItemsTemplate() + { + UpdateMenuItemsTemplate(MenuItems); + UpdateMenuItemsTemplate(FooterMenuItems); + } + + protected virtual void UpdateSelectionForMenuItems(IList? list) + { + if (list is null) + return; + + foreach (var singleMenuItem in list) + { + if (singleMenuItem is not NavigationViewItem navigationViewItem) + continue; + + if (navigationViewItem == SelectedItem) + { + navigationViewItem.IsActive = true; + + if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) + symbolIcon.Filled = true; + } + else + { + navigationViewItem.IsActive = false; + + if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) + symbolIcon.Filled = false; + } + + if (navigationViewItem.MenuItems is not IEnumerable enumerableSubMenuItems) + continue; + + foreach (var singleSubMenuItem in enumerableSubMenuItems) + { + if (singleSubMenuItem is not NavigationViewItem navigationViewSubItem) + continue; + + if (!navigationViewItem.IsExpanded && navigationViewSubItem == SelectedItem) + { + navigationViewItem.IsExpanded = true; + //navigationViewItem.BringIntoView(); + } + + navigationViewSubItem.IsActive = navigationViewSubItem == SelectedItem; + } + } + } + + protected virtual void UpdateSelectionForMenuItems() + { + UpdateSelectionForMenuItems(MenuItems); + UpdateSelectionForMenuItems(FooterMenuItems); + } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index cabe44f43..c63421d61 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -62,7 +62,7 @@ public bool ReplaceContent(Type? pageTypeToEmbed) if (_serviceProvider != null) { - UpdateContent(_serviceProvider.GetService(pageTypeToEmbed) ?? null!, null!); + UpdateContent(_serviceProvider.GetService(pageTypeToEmbed)); return true; } @@ -70,19 +70,13 @@ public bool ReplaceContent(Type? pageTypeToEmbed) if (_pageService == null) return false; - UpdateContent(_pageService.GetPage(pageTypeToEmbed) ?? null!, null!); + UpdateContent(_pageService.GetPage(pageTypeToEmbed)); return true; } /// - public bool ReplaceContent(UIElement pageInstanceToEmbed) - { - return ReplaceContent(pageInstanceToEmbed, null!); - } - - /// - public bool ReplaceContent(UIElement pageInstanceToEmbed, object dataContext) + public bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataContext = null) { UpdateContent(pageInstanceToEmbed, dataContext); @@ -100,7 +94,7 @@ public bool GoForward() if (_currentIndexInJournal > _journal.Count - 1) return false; - return Navigate(_journal[_currentIndexInJournal], null!); + return Navigate(_journal[_currentIndexInJournal]); } /// @@ -142,7 +136,9 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, SelectedItem = viewItem; - UpdateSelectionForMenuItems(); + UpdateSelectionForMenuItems(MenuItems); + UpdateSelectionForMenuItems(FooterMenuItems); + OnSelectionChanged(); if (bringIntoView && viewItem is FrameworkElement frameworkElement) @@ -157,9 +153,10 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, private void UpdateJournal(INavigationViewItem viewItem) { #if DEBUG - System.Diagnostics.Debug.WriteLine($"JOURNAL INDEX {_currentIndexInJournal}"); + Debug.WriteLine($"JOURNAL INDEX {_currentIndexInJournal}"); + if (_journal.Count > 0) - System.Diagnostics.Debug.WriteLine($"JOURNAL LAST ELEMENT {_journal[_journal.Count - 1]}"); + Debug.WriteLine($"JOURNAL LAST ELEMENT {_journal[_journal.Count - 1]}"); #endif if (_journal.Count == 0) @@ -216,93 +213,11 @@ private void RenderSelectedItemContent(INavigationViewItem viewItem, object? dat UpdateContent(pageInstance, dataContext); } - private void UpdateContent(object? content, object? dataContext) + private void UpdateContent(object? content, object? dataContext = null) { if (dataContext != null && content is FrameworkElement frameworkViewContent) frameworkViewContent.DataContext = dataContext; NavigationViewContentPresenter.Navigate(content); } - - private void UpdateSelectionForMenuItems() - { - if (MenuItems is IEnumerable enumerableMenuItems) - { - foreach (var singleMenuItem in enumerableMenuItems) - { - if (singleMenuItem is not NavigationViewItem navigationViewItem) - continue; - - if (navigationViewItem == SelectedItem) - { - navigationViewItem.IsActive = true; - - if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - symbolIcon.Filled = true; - } - else - { - navigationViewItem.IsActive = false; - - if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - symbolIcon.Filled = false; - } - - if (navigationViewItem.MenuItems is IEnumerable enumerableSubMenuItems) - { - foreach (var singleSubMenuItem in enumerableSubMenuItems) - { - if (singleSubMenuItem is not NavigationViewItem navigationViewSubItem) - continue; - - if (!navigationViewItem.IsExpanded && navigationViewSubItem == SelectedItem) - { - navigationViewItem.IsExpanded = true; - //navigationViewItem.BringIntoView(); - } - - navigationViewSubItem.IsActive = navigationViewSubItem == SelectedItem; - } - } - } - } - - if (FooterMenuItems is IEnumerable enumerableFooterMenuItems) - { - foreach (var singleFooterMenuItem in enumerableFooterMenuItems) - { - if (singleFooterMenuItem is not NavigationViewItem navigationViewItem) - continue; - - if (navigationViewItem == SelectedItem) - { - navigationViewItem.IsActive = true; - - if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - symbolIcon.Filled = true; - } - else - { - navigationViewItem.IsActive = false; - } - - if (navigationViewItem.MenuItems is IEnumerable enumerableSubMenuItems) - { - foreach (var singleSubMenuItem in enumerableSubMenuItems) - { - if (singleSubMenuItem is not NavigationViewItem navigationViewSubItem) - continue; - - if (!navigationViewItem.IsExpanded && navigationViewSubItem == SelectedItem) - { - navigationViewItem.IsExpanded = true; - //navigationViewItem.BringIntoView(); - } - - navigationViewSubItem.IsActive = navigationViewSubItem == SelectedItem; - } - } - } - } - } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewActivator.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewActivator.cs index 59bbde6f2..5d4a2ecbc 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationViewActivator.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationViewActivator.cs @@ -17,23 +17,13 @@ namespace Wpf.Ui.Controls.Navigation; /// internal static class NavigationViewActivator { - /// - /// Creates new instance of type derived from . - /// - /// to instantiate. - /// Instance of the object or . - public static FrameworkElement CreateInstance(Type pageType) - { - return CreateInstance(pageType, null!); - } - /// /// Creates new instance of type derived from . /// /// to instantiate. /// Additional context to set. /// Instance of the object or . - public static FrameworkElement CreateInstance(Type pageType, object? dataContext) + public static FrameworkElement? CreateInstance(Type pageType, object? dataContext = null) { if (!typeof(FrameworkElement).IsAssignableFrom(pageType)) throw new InvalidCastException( @@ -42,7 +32,7 @@ public static FrameworkElement CreateInstance(Type pageType, object? dataContext if (DesignerHelper.IsInDesignMode) return new Page { Content = new TextBlock { Text = "Pages are not rendered while using the Designer. Edit the page template directly." } }; - var instance = null as FrameworkElement; + FrameworkElement? instance; #if NET48_OR_GREATER || NETCOREAPP3_0_OR_GREATER if (ControlsServices.ControlsServiceProvider != null) From 19d338fc9b84689470b8d554496a9176603005ee Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Thu, 26 Jan 2023 12:52:40 +0600 Subject: [PATCH 08/27] stared implementing navigation stack --- .../Navigation/INavigationViewItem.cs | 2 +- .../Navigation/NavigationView.Base.cs | 85 +------- .../Navigation/NavigationView.Navigation.cs | 203 +++++++++++++----- .../Navigation/NavigationView.Properties.cs | 22 +- .../Controls/Navigation/NavigationViewItem.cs | 2 +- 5 files changed, 156 insertions(+), 158 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs b/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs index 82ea73cf0..41e74ff73 100644 --- a/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs +++ b/src/Wpf.Ui/Controls/Navigation/INavigationViewItem.cs @@ -48,7 +48,7 @@ public interface INavigationViewItem /// /// Gets information whether the current element is active. /// - bool IsActive { get; } + bool IsActive { get; set; } /// /// Gets information whether the sub- are expanded. diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs index e5dba3100..3aeb99786 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Base.cs @@ -33,7 +33,7 @@ public partial class NavigationView : System.Windows.Controls.Control, INavigati protected Dictionary PageTypeNavigationViewsDictionary = new(); /// - public INavigationViewItem? SelectedItem { get; private set; } + public INavigationViewItem? SelectedItem { get; protected set; } /// /// Static constructor which overrides default property metadata. @@ -78,7 +78,7 @@ protected override void OnInitialized(EventArgs e) UpdateLayout(); UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); + //UpdateSelectionForMenuItems(); AddItemsToDictionaries(); } @@ -97,6 +97,11 @@ protected virtual void OnUnloaded(object sender, RoutedEventArgs e) Unloaded -= OnUnloaded; SizeChanged -= OnSizeChanged; + PageIdOrTargetTagNavigationViewsDictionary.Clear(); + PageTypeNavigationViewsDictionary.Clear(); + + ClearJournal(); + if (AutoSuggestBox is not null) AutoSuggestBox.SuggestionChosen -= AutoSuggestBoxOnSuggestionChosen; @@ -127,32 +132,6 @@ protected virtual void OnToggleButtonClick(object sender, RoutedEventArgs e) Debug.WriteLine("Toggle"); } - /// - /// This virtual method is called when source of the menu items is changed. - /// - protected virtual void OnMenuItemsChanged() - { - InvalidateArrange(); - InvalidateVisual(); - UpdateLayout(); - - UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); - - AddItemsToDictionaries(MenuItems); - } - - /// - /// This virtual method is called when source of the footer menu items is changed. - /// - protected virtual void OnFooterMenuItemsChanged() - { - UpdateAutoSuggestBoxSuggestions(); - UpdateSelectionForMenuItems(); - - AddItemsToDictionaries(FooterMenuItems); - } - /// /// This virtual method is called when is changed. /// @@ -326,54 +305,4 @@ protected virtual void UpdateMenuItemsTemplate() UpdateMenuItemsTemplate(MenuItems); UpdateMenuItemsTemplate(FooterMenuItems); } - - protected virtual void UpdateSelectionForMenuItems(IList? list) - { - if (list is null) - return; - - foreach (var singleMenuItem in list) - { - if (singleMenuItem is not NavigationViewItem navigationViewItem) - continue; - - if (navigationViewItem == SelectedItem) - { - navigationViewItem.IsActive = true; - - if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - symbolIcon.Filled = true; - } - else - { - navigationViewItem.IsActive = false; - - if (navigationViewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - symbolIcon.Filled = false; - } - - if (navigationViewItem.MenuItems is not IEnumerable enumerableSubMenuItems) - continue; - - foreach (var singleSubMenuItem in enumerableSubMenuItems) - { - if (singleSubMenuItem is not NavigationViewItem navigationViewSubItem) - continue; - - if (!navigationViewItem.IsExpanded && navigationViewSubItem == SelectedItem) - { - navigationViewItem.IsExpanded = true; - //navigationViewItem.BringIntoView(); - } - - navigationViewSubItem.IsActive = navigationViewSubItem == SelectedItem; - } - } - } - - protected virtual void UpdateSelectionForMenuItems() - { - UpdateSelectionForMenuItems(MenuItems); - UpdateSelectionForMenuItems(FooterMenuItems); - } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index c63421d61..86b18b120 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -10,6 +10,8 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Reflection; using System.Windows; using Wpf.Ui.Contracts; @@ -17,16 +19,20 @@ namespace Wpf.Ui.Controls.Navigation; public partial class NavigationView { - private readonly List _journal = new(); + protected readonly List Journal = new(); + protected readonly List NavigationStack = new(); + + private readonly Dictionary _complexNavigationStackHistory = new(); private IServiceProvider? _serviceProvider; private IPageService? _pageService; - private int _currentIndexInJournal = 0; + private int _currentIndexInJournal; + private bool _isBackwardsNavigated; /// public bool CanGoBack - => _journal.Count > 1 && _currentIndexInJournal >= 0; + => Journal.Count > 1 && _currentIndexInJournal >= 0; /// public void SetPageService(IPageService pageService) @@ -37,7 +43,7 @@ public void SetServiceProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; /// - public bool Navigate(Type pageType, object? dataContext = null) + public virtual bool Navigate(Type pageType, object? dataContext = null) { if (!PageTypeNavigationViewsDictionary.TryGetValue(pageType, out var navigationViewItem)) return false; @@ -46,7 +52,7 @@ public bool Navigate(Type pageType, object? dataContext = null) } /// - public bool Navigate(string pageIdOrTargetTag, object? dataContext = null) + public virtual bool Navigate(string pageIdOrTargetTag, object? dataContext = null) { if (!PageIdOrTargetTagNavigationViewsDictionary.TryGetValue(pageIdOrTargetTag, out var navigationViewItem)) return false; @@ -55,7 +61,7 @@ public bool Navigate(string pageIdOrTargetTag, object? dataContext = null) } /// - public bool ReplaceContent(Type? pageTypeToEmbed) + public virtual bool ReplaceContent(Type? pageTypeToEmbed) { if (pageTypeToEmbed == null) return false; @@ -76,7 +82,7 @@ public bool ReplaceContent(Type? pageTypeToEmbed) } /// - public bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataContext = null) + public virtual bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataContext = null) { UpdateContent(pageInstanceToEmbed, dataContext); @@ -84,49 +90,44 @@ public bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataContext = } /// - public bool GoForward() + public virtual bool GoForward() { - if (_journal.Count <= 1) + if (Journal.Count <= 1) return false; _currentIndexInJournal += 1; - if (_currentIndexInJournal > _journal.Count - 1) + if (_currentIndexInJournal > Journal.Count - 1) return false; - return Navigate(_journal[_currentIndexInJournal]); + return Navigate(Journal[_currentIndexInJournal]); } /// - public bool GoBack() + public virtual bool GoBack() { - if (_journal.Count <= 1) + if (Journal.Count <= 1) return false; - _currentIndexInJournal -= 1; - - if (_currentIndexInJournal < 0) - return false; - - return Navigate(_journal[_currentIndexInJournal], null!); + var itemId = Journal[Journal.Count - 2]; + _isBackwardsNavigated = true; + return Navigate(itemId); } /// - public void ClearJournal() + public virtual void ClearJournal() { - _journal.Clear(); + Journal.Clear(); + NavigationStack.Clear(); + _complexNavigationStackHistory.Clear(); _currentIndexInJournal = 0; } private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, bool notifyAboutUpdate, bool bringIntoView) { - if (viewItem == SelectedItem) + if (NavigationStack.Count > 0 && NavigationStack[NavigationStack.Count -1] == viewItem) return false; - UpdateJournal(viewItem); - - IsBackEnabled = _journal.Count > 0; - Debug.WriteLine($"DEBUG | {viewItem.Id} - {viewItem.TargetPageTag ?? "NO_TAG"} | NAVIGATED"); RenderSelectedItemContent(viewItem, dataContext); @@ -134,11 +135,10 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, if (!notifyAboutUpdate) return true; - SelectedItem = viewItem; - - UpdateSelectionForMenuItems(MenuItems); - UpdateSelectionForMenuItems(FooterMenuItems); + UpdateCurrentNavigationStackItem(viewItem); + AddToJournal(viewItem); + UpdateSelectionForMenuItem(viewItem); OnSelectionChanged(); if (bringIntoView && viewItem is FrameworkElement frameworkElement) @@ -150,34 +150,10 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, return true; } - private void UpdateJournal(INavigationViewItem viewItem) + private void AddToJournal(INavigationViewItem viewItem) { -#if DEBUG - Debug.WriteLine($"JOURNAL INDEX {_currentIndexInJournal}"); - - if (_journal.Count > 0) - Debug.WriteLine($"JOURNAL LAST ELEMENT {_journal[_journal.Count - 1]}"); -#endif - - if (_journal.Count == 0) - { - _currentIndexInJournal = 0; - _journal.Add(viewItem.Id); - - return; - } - - // TODO: Fix at last position - - if (_currentIndexInJournal == _journal.Count - 1) - { - _journal.Add(viewItem.Id); - - _currentIndexInJournal++; - } - - if (_journal.Count > 20) - _journal.RemoveAt(0); + Journal.Add(viewItem.Id); + IsBackEnabled = CanGoBack; } private void RenderSelectedItemContent(INavigationViewItem viewItem, object? dataContext) @@ -215,9 +191,120 @@ private void RenderSelectedItemContent(INavigationViewItem viewItem, object? dat private void UpdateContent(object? content, object? dataContext = null) { - if (dataContext != null && content is FrameworkElement frameworkViewContent) + if (dataContext is not null && content is FrameworkElement frameworkViewContent) frameworkViewContent.DataContext = dataContext; NavigationViewContentPresenter.Navigate(content); } + + private void AddToNavigationStack(INavigationViewItem viewItem) + { + if (!NavigationStack.Contains(viewItem)) + NavigationStack.Add(viewItem); + + if (NavigationStack.Count > 1) + AddToNavigationStackHistory(viewItem); + + SelectedItem = NavigationStack[NavigationStack.Count - 1]; + } + + private void UpdateCurrentNavigationStackItem(INavigationViewItem viewItem) + { + if (NavigationStack.Contains(viewItem)) + return; + + if (NavigationStack.Count == 0) + { + NavigationStack.Add(viewItem); + } + else + { + NavigationStack[0] = viewItem; + } + + SelectedItem = NavigationStack[0]; + ClearNavigationStack(1); + } + + private void RecreateBreadcrumbsFromHistory(INavigationViewItem item) + { + + } + + private void AddToNavigationStackHistory(INavigationViewItem viewItem) + { + var lastItem = NavigationStack[NavigationStack.Count - 1]; + var startIndex = NavigationStack.IndexOf(viewItem); + + if (startIndex < 0) + startIndex = 0; + + _complexNavigationStackHistory.Add(lastItem, new INavigationViewItem[NavigationStack.Count - 1 - startIndex]); + + int i = 0; + for (int j = startIndex; j < NavigationStack.Count - 1; j++) + { + _complexNavigationStackHistory[lastItem][i] = NavigationStack[j]; + i++; + } + } + + private void ClearNavigationStack(int navigationStackItemIndex) + { + var navigationStackCount = NavigationStack.Count; + var length = navigationStackCount - navigationStackItemIndex; + + if (length == 0) + return; + + INavigationViewItem[] buffer; + +#if NET6_0_OR_GREATER + + buffer = System.Buffers.ArrayPool.Shared.Rent(length); +#else + buffer = new INavigationViewItem[length]; +#endif + + int i = 0; + for (int j = navigationStackItemIndex; j <= navigationStackCount - 1; j++) + { + buffer[i] = NavigationStack[j]; + i++; + } + + for (var index = 0; index < length; index++) + { + var item = buffer[index]; + NavigationStack.Remove(item); + } + +#if NET6_0_OR_GREATER + System.Buffers.ArrayPool.Shared.Return(buffer, true); +#endif + } + + private void ClearNavigationStack(INavigationViewItem item) + { + + } + + private void UpdateSelectionForMenuItem(INavigationViewItem viewItem) + { + viewItem.IsActive = true; + + if (viewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) + symbolIcon.Filled = true; + + if (Journal.Count == 1) + return; + + if (!PageIdOrTargetTagNavigationViewsDictionary.TryGetValue(Journal[Journal.Count - 2], out var previousItem)) + return; + + previousItem.IsActive = false; + + if (previousItem.Icon is SymbolIcon previousSymbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) + previousSymbolIcon.Filled = false; + } } diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs index 7ecd95a06..f1c7175c0 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Properties.cs @@ -42,8 +42,7 @@ public partial class NavigationView /// Property for . /// public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register(nameof(MenuItems), - typeof(IList), typeof(NavigationView), - new PropertyMetadata(OnMenuItemsPropertyChanged)); + typeof(IList), typeof(NavigationView)); /// /// Property for . @@ -56,8 +55,7 @@ public partial class NavigationView /// Property for . /// public static readonly DependencyProperty FooterMenuItemsProperty = DependencyProperty.Register(nameof(FooterMenuItemsProperty), - typeof(IList), typeof(NavigationView), - new PropertyMetadata(OnFooterMenuItemsPropertyChanged)); + typeof(IList), typeof(NavigationView)); /// /// Property for . @@ -343,14 +341,6 @@ public TransitionType TransitionType set => SetValue(TransitionTypeProperty, value); } - private static void OnMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) - { - if (d is not NavigationView { IsInitialized: true } navigationView) - return; - - navigationView.OnMenuItemsChanged(); - } - private static void OnMenuItemsSourcePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) @@ -359,14 +349,6 @@ private static void OnMenuItemsSourcePropertyChanged(DependencyObject? d, Depend navigationView.MenuItems = enumerableNewValue; } - private static void OnFooterMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) - { - if (d is not NavigationView { IsInitialized: true } navigationView) - return; - - navigationView.OnFooterMenuItemsChanged(); - } - private static void OnFooterMenuItemsSourcePropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs b/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs index cdbe14364..d69934740 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationViewItem.cs @@ -113,7 +113,7 @@ public bool HasMenuItems public bool IsActive { get => (bool)GetValue(IsActiveProperty); - internal set => SetValue(IsActiveProperty, value); + set => SetValue(IsActiveProperty, value); } /// From 837553b14165dabfee155a082d9ec50597b92a19 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Thu, 26 Jan 2023 13:38:54 +0600 Subject: [PATCH 09/27] fixed backwards navigation --- .../Navigation/NavigationView.Navigation.cs | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs index 86b18b120..968c5de51 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationView.Navigation.cs @@ -19,7 +19,7 @@ namespace Wpf.Ui.Controls.Navigation; public partial class NavigationView { - protected readonly List Journal = new(); + protected readonly List Journal = new(200); protected readonly List NavigationStack = new(); private readonly Dictionary _complexNavigationStackHistory = new(); @@ -27,8 +27,8 @@ public partial class NavigationView private IServiceProvider? _serviceProvider; private IPageService? _pageService; - private int _currentIndexInJournal; private bool _isBackwardsNavigated; + private int _currentIndexInJournal; /// public bool CanGoBack @@ -92,6 +92,8 @@ public virtual bool ReplaceContent(UIElement pageInstanceToEmbed, object? dataCo /// public virtual bool GoForward() { + throw new NotImplementedException(); + if (Journal.Count <= 1) return false; @@ -109,8 +111,12 @@ public virtual bool GoBack() if (Journal.Count <= 1) return false; - var itemId = Journal[Journal.Count - 2]; + if (_currentIndexInJournal <= 1) + return false; + + var itemId = Journal[_currentIndexInJournal - 2]; _isBackwardsNavigated = true; + return Navigate(itemId); } @@ -135,11 +141,9 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, if (!notifyAboutUpdate) return true; - UpdateCurrentNavigationStackItem(viewItem); AddToJournal(viewItem); - - UpdateSelectionForMenuItem(viewItem); - OnSelectionChanged(); + UpdateCurrentNavigationStackItem(viewItem); + if (bringIntoView && viewItem is FrameworkElement frameworkElement) { @@ -152,7 +156,25 @@ private bool NavigateInternal(INavigationViewItem viewItem, object? dataContext, private void AddToJournal(INavigationViewItem viewItem) { +#if DEBUG + Debug.WriteLine($"JOURNAL INDEX {_currentIndexInJournal}"); + if (Journal.Count > 0) + Debug.WriteLine($"JOURNAL LAST ELEMENT {Journal[Journal.Count - 1]}"); +#endif + + if (_isBackwardsNavigated) + { + _isBackwardsNavigated = false; + + Journal.RemoveAt(Journal.LastIndexOf(Journal[Journal.Count - 2])); + Journal.RemoveAt(Journal.LastIndexOf(Journal[Journal.Count - 1])); + + _currentIndexInJournal -= 2; + } + Journal.Add(viewItem.Id); + _currentIndexInJournal++; + IsBackEnabled = CanGoBack; } @@ -200,7 +222,11 @@ private void UpdateContent(object? content, object? dataContext = null) private void AddToNavigationStack(INavigationViewItem viewItem) { if (!NavigationStack.Contains(viewItem)) + { + ActivateMenuItem(viewItem); NavigationStack.Add(viewItem); + _breadcrumbBarItems.Add(new NavigationViewBreadcrumbItem(viewItem)); + } if (NavigationStack.Count > 1) AddToNavigationStackHistory(viewItem); @@ -215,14 +241,22 @@ private void UpdateCurrentNavigationStackItem(INavigationViewItem viewItem) if (NavigationStack.Count == 0) { + ActivateMenuItem(viewItem); NavigationStack.Add(viewItem); + _breadcrumbBarItems.Add(new NavigationViewBreadcrumbItem(viewItem)); } else { + DeactivateMenuItem(NavigationStack[0]); NavigationStack[0] = viewItem; + ActivateMenuItem(NavigationStack[0]); + + _breadcrumbBarItems[0] = new NavigationViewBreadcrumbItem(viewItem); } SelectedItem = NavigationStack[0]; + OnSelectionChanged(); + ClearNavigationStack(1); } @@ -289,22 +323,21 @@ private void ClearNavigationStack(INavigationViewItem item) } - private void UpdateSelectionForMenuItem(INavigationViewItem viewItem) + private void ActivateMenuItem(INavigationViewItem viewItem) { viewItem.IsActive = true; if (viewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) symbolIcon.Filled = true; - if (Journal.Count == 1) - return; + } - if (!PageIdOrTargetTagNavigationViewsDictionary.TryGetValue(Journal[Journal.Count - 2], out var previousItem)) - return; + private void DeactivateMenuItem(INavigationViewItem viewItem) + { + viewItem.IsActive = false; - previousItem.IsActive = false; + if (viewItem.Icon is SymbolIcon symbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) + symbolIcon.Filled = false; - if (previousItem.Icon is SymbolIcon previousSymbolIcon && PaneDisplayMode == NavigationViewPaneDisplayMode.LeftFluent) - previousSymbolIcon.Filled = false; } } From 3ff6db0737233f81d9fd35e94ff21f1fda660d25 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:00:09 +0600 Subject: [PATCH 10/27] added multilevel navigation demo page --- src/Wpf.Ui.Gallery/App.xaml.cs | 7 ++++ .../ViewModels/Windows/MainWindowViewModel.cs | 1 + .../Navigation/MultilevelNavigationPage.xaml | 20 +++++++++++ .../MultilevelNavigationPage.xaml.cs | 21 ++++++++++++ .../MultilevelNavigationSamplePage1.xaml | 21 ++++++++++++ .../MultilevelNavigationSamplePage1.xaml.cs | 20 +++++++++++ .../MultilevelNavigationSamplePage2.xaml | 21 ++++++++++++ .../MultilevelNavigationSamplePage2.xaml.cs | 20 +++++++++++ .../MultilevelNavigationSamplePage3.xaml | 21 ++++++++++++ .../MultilevelNavigationSamplePage3.xaml.cs | 20 +++++++++++ src/Wpf.Ui/Contracts/INavigationService.cs | 14 ++++++++ .../Controls/Navigation/INavigationView.cs | 16 +++++++++ .../Navigation/NavigationView.Base.cs | 4 +-- .../Navigation/NavigationView.Navigation.cs | 34 ++++++++++++++----- .../Navigation/NavigationView.Properties.cs | 26 ++++++++++++-- src/Wpf.Ui/Services/NavigationService.cs | 24 +++++++++++-- 16 files changed, 275 insertions(+), 15 deletions(-) create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Navigation/MultilevelNavigationPage.xaml create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Navigation/MultilevelNavigationPage.xaml.cs create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage1.xaml create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage1.xaml.cs create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage2.xaml create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage2.xaml.cs create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage3.xaml create mode 100644 src/Wpf.Ui.Gallery/Views/Pages/Samples/MultilevelNavigationSamplePage3.xaml.cs diff --git a/src/Wpf.Ui.Gallery/App.xaml.cs b/src/Wpf.Ui.Gallery/App.xaml.cs index b3fa34b84..79014b74e 100644 --- a/src/Wpf.Ui.Gallery/App.xaml.cs +++ b/src/Wpf.Ui.Gallery/App.xaml.cs @@ -29,6 +29,7 @@ using Wpf.Ui.Gallery.Views.Pages.Icons; using Wpf.Ui.Gallery.Views.Pages.Media; using Wpf.Ui.Gallery.Views.Pages.Navigation; +using Wpf.Ui.Gallery.Views.Pages.Samples; using Wpf.Ui.Gallery.Views.Pages.StatusAndInfo; using Wpf.Ui.Gallery.Views.Pages.Text; using Wpf.Ui.Gallery.Views.Pages.Windows; @@ -149,10 +150,16 @@ public partial class App : Application services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); + // Multilevel navigation sample Pages + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + // Status and Info services.AddTransient(); services.AddTransient(); diff --git a/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs index 3a64ec25c..f5078271a 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs @@ -91,6 +91,7 @@ public MainWindowViewModel(IServiceProvider serviceProvider) { new NavigationViewItem { Content = "BreadcrumbBar", TargetPageType = typeof(BreadcrumbBarPage) }, new NavigationViewItem { Content = "NavigationView", TargetPageType = typeof(NavigationViewPage) }, + new NavigationViewItem { Content = "Multilevel navigation demo", TargetPageType = typeof(MultilevelNavigationPage) }, new NavigationViewItem { Content = "TabControl", TargetPageType = typeof(TabControlPage) }, }}, new NavigationViewItem {Content = "Status and Info", Icon = new SymbolIcon { Symbol = SymbolRegular.ChatBubblesQuestion24 }, TargetPageType = typeof(StatusAndInfoPage), MenuItems = new ObservableCollection diff --git a/src/Wpf.Ui.Gallery/Views/Pages/Navigation/MultilevelNavigationPage.xaml b/src/Wpf.Ui.Gallery/Views/Pages/Navigation/MultilevelNavigationPage.xaml new file mode 100644 index 000000000..40bdaeaef --- /dev/null +++ b/src/Wpf.Ui.Gallery/Views/Pages/Navigation/MultilevelNavigationPage.xaml @@ -0,0 +1,20 @@ + + + +