using WPFluent.Animations; using System.Collections; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Windows.Controls; // ReSharper disable once CheckNamespace namespace WPFluent.Controls; /// /// Defines the dependency properties and dp callbacks for control /// public partial class NavigationView { private static readonly DependencyPropertyKey FooterMenuItemsPropertyKey = DependencyProperty.RegisterReadOnly( nameof(FooterMenuItems), typeof(ObservableCollection), typeof(NavigationView), new PropertyMetadata(null)); private static readonly DependencyPropertyKey MenuItemsPropertyKey = DependencyProperty.RegisterReadOnly( nameof(MenuItems), typeof(ObservableCollection), typeof(NavigationView), new PropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty AlwaysShowHeaderProperty = DependencyProperty.Register( nameof(AlwaysShowHeader), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(false)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty AutoSuggestBoxProperty = DependencyProperty.Register( nameof(AutoSuggestBox), typeof(AutoSuggestBox), typeof(NavigationView), new FrameworkPropertyMetadata(null, OnAutoSuggestBoxChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty BreadcrumbBarProperty = DependencyProperty.Register( nameof(BreadcrumbBar), typeof(Controls.BreadcrumbBar), typeof(NavigationView), new FrameworkPropertyMetadata(null, OnBreadcrumbBarChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty CompactPaneLengthProperty = DependencyProperty.Register( nameof(CompactPaneLength), typeof(double), typeof(NavigationView), new FrameworkPropertyMetadata(0D)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty ContentOverlayProperty = DependencyProperty.Register( nameof(ContentOverlay), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty EnableDebugMessagesProperty = DependencyProperty.Register( nameof(EnableDebugMessages), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(false)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty FooterMenuItemsProperty = FooterMenuItemsPropertyKey.DependencyProperty; /// /// Identifies the dependency property. /// public static readonly DependencyProperty FooterMenuItemsSourceProperty = DependencyProperty.Register( nameof(FooterMenuItemsSource), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null, OnFooterMenuItemsSourceChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty FrameMarginProperty = DependencyProperty.Register( nameof(FrameMargin), typeof(Thickness), typeof(NavigationView), new FrameworkPropertyMetadata(default(Thickness))); /// /// Identifies the dependency property. /// public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( nameof(Header), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty HeaderVisibilityProperty = DependencyProperty.Register( nameof(HeaderVisibility), typeof(Visibility), typeof(NavigationView), new FrameworkPropertyMetadata(Visibility.Visible)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register( nameof(IsBackButtonVisible), typeof(NavigationViewBackButtonVisible), typeof(NavigationView), new FrameworkPropertyMetadata(NavigationViewBackButtonVisible.Auto)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsBackEnabledProperty = DependencyProperty.Register( nameof(IsBackEnabled), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(false)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsPaneOpenProperty = DependencyProperty.Register( nameof(IsPaneOpen), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(true, OnIsPaneOpenChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsPaneToggleVisibleProperty = DependencyProperty.Register( nameof(IsPaneToggleVisible), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(true)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsPaneVisibleProperty = DependencyProperty.Register( nameof(IsPaneVisible), typeof(bool), typeof(NavigationView), new FrameworkPropertyMetadata(false)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register( nameof(ItemTemplate), typeof(ControlTemplate), typeof(NavigationView), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, OnItemTemplateChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty MenuItemsProperty = MenuItemsPropertyKey.DependencyProperty; /// /// Identifies the dependency property. /// public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.Register( nameof(MenuItemsSource), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null, OnMenuItemsSourceChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty OpenPaneLengthProperty = DependencyProperty.Register( nameof(OpenPaneLength), typeof(double), typeof(NavigationView), new FrameworkPropertyMetadata(0D)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty PaneDisplayModeProperty = DependencyProperty.Register( nameof(PaneDisplayMode), typeof(NavigationViewPaneDisplayMode), typeof(NavigationView), new FrameworkPropertyMetadata(NavigationViewPaneDisplayMode.Left, OnPaneDisplayModeChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty PaneFooterProperty = DependencyProperty.Register( nameof(PaneFooter), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty PaneHeaderProperty = DependencyProperty.Register( nameof(PaneHeader), typeof(object), typeof(NavigationView), new FrameworkPropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty PaneTitleProperty = DependencyProperty.Register( nameof(PaneTitle), typeof(string), typeof(NavigationView), new FrameworkPropertyMetadata(null)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TitleBarProperty = DependencyProperty.Register( nameof(TitleBar), typeof(TitleBar), typeof(NavigationView), new FrameworkPropertyMetadata(null, OnTitleBarChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TransitionDurationProperty = DependencyProperty.Register( nameof(TransitionDuration), typeof(int), typeof(NavigationView), new FrameworkPropertyMetadata(200)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TransitionProperty = DependencyProperty.Register( nameof(Transition), typeof(Transition), typeof(NavigationView), new FrameworkPropertyMetadata(Transition.FadeInWithSlide)); private static void OnAutoSuggestBoxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } if(e.NewValue is null && e.OldValue is AutoSuggestBox oldValue) { oldValue.SuggestionChosen -= navigationView.AutoSuggestBoxOnSuggestionChosen; oldValue.QuerySubmitted -= navigationView.AutoSuggestBoxOnQuerySubmitted; return; } if(e.NewValue is not AutoSuggestBox autoSuggestBox) { return; } autoSuggestBox.OriginalItemsSource = navigationView._autoSuggestBoxItems; autoSuggestBox.SuggestionChosen += navigationView.AutoSuggestBoxOnSuggestionChosen; autoSuggestBox.QuerySubmitted += navigationView.AutoSuggestBoxOnQuerySubmitted; if(navigationView.TitleBar?.Margin == TitleBarPaneOpenMarginDefault && autoSuggestBox.Margin is { Bottom: 0, Left: 0, Right: 0, Top: 0 }) { autoSuggestBox.Margin = AutoSuggestBoxMarginDefault; } } private static void OnBreadcrumbBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } if(e.NewValue is null && e.OldValue is Controls.BreadcrumbBar oldValue) { oldValue.ItemClicked -= navigationView.BreadcrumbBarOnItemClicked; { return; } } if(e.NewValue is not Controls.BreadcrumbBar breadcrumbBar) { return; } breadcrumbBar.ItemsSource = navigationView._breadcrumbBarItems; breadcrumbBar.ItemTemplate ??= UiApplication.Current.TryFindResource("NavigationViewItemDataTemplate") as DataTemplate; breadcrumbBar.ItemClicked += navigationView.BreadcrumbBarOnItemClicked; } private void OnFooterMenuItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if(e.NewItems is null) { return; } UpdateMenuItemsTemplate(e.NewItems); AddItemsToDictionaries(e.NewItems); } private static void OnFooterMenuItemsSourceChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } navigationView.FooterMenuItems.Clear(); if(e.NewValue is IEnumerable newItemsSource and not string) { foreach(var item in newItemsSource) { navigationView.FooterMenuItems.Add(item); } } else if(e.NewValue != null) { navigationView.FooterMenuItems.Add(e.NewValue); } if(e.NewValue is INotifyCollectionChanged oc) { oc.CollectionChanged += (s, e) => navigationView.OnMenuItemsSource_CollectionChanged( oc, navigationView.FooterMenuItems, e); } } private static void OnIsPaneOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } if((bool)e.NewValue == (bool)e.OldValue) { return; } if(navigationView.IsPaneOpen) { navigationView.OnPaneOpened(); } else { navigationView.OnPaneClosed(); } navigationView.CloseNavigationViewItemMenus(); navigationView.TitleBar?.SetCurrentValue( MarginProperty, navigationView.IsPaneOpen ? TitleBarPaneOpenMarginDefault : TitleBarPaneCompactMarginDefault); UpdateVisualState(navigationView); } private static void OnItemTemplateChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } navigationView.OnItemTemplateChanged(); } private void OnMenuItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if(e.NewItems is null) { return; } UpdateMenuItemsTemplate(e.NewItems); AddItemsToDictionaries(e.NewItems); } private void OnMenuItemsSource_CollectionChanged( object? sender, IList collection, NotifyCollectionChangedEventArgs e) { if(ReferenceEquals(sender, collection)) { return; } switch(e.Action) { case NotifyCollectionChangedAction.Add: if(e.NewItems is not null) { foreach(var item in e.NewItems) { collection.Add(item); } } break; case NotifyCollectionChangedAction.Remove: if(e.OldItems is not null && e.NewItems is not null) { foreach(var item in e.OldItems) { if(!e.NewItems.Contains(item)) { collection.Remove(item); } } } break; case NotifyCollectionChangedAction.Move: var moveItem = MenuItems[e.OldStartingIndex]; collection.RemoveAt(e.OldStartingIndex); collection.Insert(e.NewStartingIndex, moveItem); break; case NotifyCollectionChangedAction.Replace: collection.RemoveAt(e.OldStartingIndex); if(e.NewItems is not null) { collection.Insert(e.OldStartingIndex, e.NewItems[0]); } break; case NotifyCollectionChangedAction.Reset: collection.Clear(); break; } } private static void OnMenuItemsSourceChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } navigationView.MenuItems.Clear(); if(e.NewValue is IEnumerable newItemsSource and not string) { foreach(var item in newItemsSource) { navigationView.MenuItems.Add(item); } } else if(e.NewValue != null) { navigationView.MenuItems.Add(e.NewValue); } if(e.NewValue is INotifyCollectionChanged oc) { oc.CollectionChanged += (s, e) => navigationView.OnMenuItemsSource_CollectionChanged( oc, navigationView.MenuItems, e); } } private static void OnPaneDisplayModeChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } navigationView.OnPaneDisplayModeChanged(); } private static void OnTitleBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not NavigationView navigationView) { return; } if(e.NewValue is null && e.OldValue is TitleBar oldValue) { navigationView.FrameMargin = new Thickness(0); oldValue.Margin = new Thickness(0); if(navigationView.AutoSuggestBox?.Margin == AutoSuggestBoxMarginDefault) { navigationView.AutoSuggestBox.SetCurrentValue(MarginProperty, new Thickness(0)); } return; } if(e.NewValue is not TitleBar titleBar) { return; } navigationView.FrameMargin = FrameMarginDefault; titleBar.Margin = TitleBarPaneOpenMarginDefault; if(navigationView.AutoSuggestBox?.Margin is { Bottom: 0, Left: 0, Right: 0, Top: 0 }) { navigationView.AutoSuggestBox.SetCurrentValue(MarginProperty, AutoSuggestBoxMarginDefault); } } /// public bool AlwaysShowHeader { get => (bool)GetValue(AlwaysShowHeaderProperty); set => SetValue(AlwaysShowHeaderProperty, value); } /// public AutoSuggestBox? AutoSuggestBox { get => (AutoSuggestBox?)GetValue(AutoSuggestBoxProperty); set => SetValue(AutoSuggestBoxProperty, value); } /// public Controls.BreadcrumbBar? BreadcrumbBar { get => (Controls.BreadcrumbBar?)GetValue(BreadcrumbBarProperty); set => SetValue(BreadcrumbBarProperty, value); } /// public double CompactPaneLength { get => (double)GetValue(CompactPaneLengthProperty); set => SetValue(CompactPaneLengthProperty, value); } /// public object? ContentOverlay { get => GetValue(ContentOverlayProperty); set => SetValue(ContentOverlayProperty, value); } /// /// Gets or sets a value indicating whether debugging messages for this control are enabled /// public bool EnableDebugMessages { get => (bool)GetValue(EnableDebugMessagesProperty); set => SetValue(EnableDebugMessagesProperty, value); } /// public IList FooterMenuItems => (ObservableCollection)GetValue(FooterMenuItemsProperty); /// [Bindable(true)] public object? FooterMenuItemsSource { get => GetValue(FooterMenuItemsSourceProperty); set { if(value is null) { ClearValue(FooterMenuItemsSourceProperty); } else { SetValue(FooterMenuItemsSourceProperty, value); } } } /// public Thickness FrameMargin { get => (Thickness)GetValue(FrameMarginProperty); set => SetValue(FrameMarginProperty, value); } /// public object? Header { get => GetValue(HeaderProperty); set => SetValue(HeaderProperty, value); } /// public Visibility HeaderVisibility { get => (Visibility)GetValue(HeaderVisibilityProperty); set => SetValue(HeaderVisibilityProperty, value); } /// public NavigationViewBackButtonVisible IsBackButtonVisible { get => (NavigationViewBackButtonVisible)GetValue(IsBackButtonVisibleProperty); set => SetValue(IsBackButtonVisibleProperty, value); } /// public bool IsBackEnabled { get => (bool)GetValue(IsBackEnabledProperty); protected set => SetValue(IsBackEnabledProperty, value); } /// public bool IsPaneOpen { get => (bool)GetValue(IsPaneOpenProperty); set => SetValue(IsPaneOpenProperty, value); } /// public bool IsPaneToggleVisible { get => (bool)GetValue(IsPaneToggleVisibleProperty); set => SetValue(IsPaneToggleVisibleProperty, value); } /// public bool IsPaneVisible { get => (bool)GetValue(IsPaneVisibleProperty); set => SetValue(IsPaneVisibleProperty, value); } /// public ControlTemplate? ItemTemplate { get => (ControlTemplate?)GetValue(ItemTemplateProperty); set => SetValue(ItemTemplateProperty, value); } /// public IList MenuItems => (ObservableCollection)GetValue(MenuItemsProperty); /// [Bindable(true)] public object? MenuItemsSource { get => GetValue(MenuItemsSourceProperty); set { if(value is null) { ClearValue(MenuItemsSourceProperty); } else { SetValue(MenuItemsSourceProperty, value); } } } /// public double OpenPaneLength { get => (double)GetValue(OpenPaneLengthProperty); set => SetValue(OpenPaneLengthProperty, value); } /// public NavigationViewPaneDisplayMode PaneDisplayMode { get => (NavigationViewPaneDisplayMode)GetValue(PaneDisplayModeProperty); set => SetValue(PaneDisplayModeProperty, value); } /// public object? PaneFooter { get => GetValue(PaneFooterProperty); set => SetValue(PaneFooterProperty, value); } /// public object? PaneHeader { get => GetValue(PaneHeaderProperty); set => SetValue(PaneHeaderProperty, value); } /// public string? PaneTitle { get => (string?)GetValue(PaneTitleProperty); set => SetValue(PaneTitleProperty, value); } /// public TitleBar? TitleBar { get => (TitleBar?)GetValue(TitleBarProperty); set => SetValue(TitleBarProperty, value); } /// public Transition Transition { get => (Transition)GetValue(TransitionProperty); set => SetValue(TransitionProperty, value); } /// [Bindable(true)] [Category("Appearance")] public int TransitionDuration { get => (int)GetValue(TransitionDurationProperty); set => SetValue(TransitionDurationProperty, value); } }