/* Based on Windows UI Library */ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Navigation; using WPFluent.Abstractions; using WPFluent.Animations; // ReSharper disable once CheckNamespace namespace WPFluent.Controls; public class NavigationViewContentPresenter : Frame { /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsDynamicScrollViewerEnabledProperty = DependencyProperty.Register( nameof(IsDynamicScrollViewerEnabled), typeof(bool), typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TransitionDurationProperty = DependencyProperty.Register( nameof(TransitionDuration), typeof(int), typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(200)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TransitionProperty = DependencyProperty.Register( nameof(Transition), typeof(Transition), typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(Transition.FadeInWithSlide)); static NavigationViewContentPresenter() { DefaultStyleKeyProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(typeof(NavigationViewContentPresenter))); NavigationUIVisibilityProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(NavigationUIVisibility.Hidden)); SandboxExternalContentProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(true)); JournalOwnershipProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(JournalOwnership.UsesParentJournal)); ScrollViewer.CanContentScrollProperty.OverrideMetadata(typeof(Page), new FrameworkPropertyMetadata(true)); } public NavigationViewContentPresenter() { Navigating += static (sender, eventArgs) => { if (eventArgs.Content is null) { return; } var self = (NavigationViewContentPresenter)sender; self.OnNavigating(eventArgs); }; Navigated += static (sender, eventArgs) => { var self = (NavigationViewContentPresenter)sender; if (eventArgs.Content is null) { return; } self.OnNavigated(eventArgs); }; } private void ApplyTransitionEffectToNavigatedPage(object content) { if (TransitionDuration < 1) { return; } TransitionAnimationProvider.ApplyTransition(content, Transition, TransitionDuration); } [System.Diagnostics.CodeAnalysis.SuppressMessage( "ReSharper", "SuspiciousTypeConversion.Global", Justification = "The library user might make a class inherit from both FrameworkElement and INavigationAware at the same time.")] private static void NotifyContentAboutNavigating(object content, Func function) { // The order in which the OnNavigatedToAsync/OnNavigatedFromAsync methods of View and ViewModel are called // is not guaranteed if (content is INavigationAware navigationAwareContent) { function(navigationAwareContent); } if (content is INavigableView { ViewModel: INavigationAware navigationAwareViewModel }) { function(navigationAwareViewModel); } else if (content is FrameworkElement { DataContext: INavigationAware viewModel } && !ReferenceEquals(viewModel, content)) { function(viewModel); } } private static void NotifyContentAboutNavigatingFrom(object content) { NotifyContentAboutNavigating(content, navigationAware => navigationAware.OnNavigatedFromAsync()); } private static void NotifyContentAboutNavigatingTo(object content) { NotifyContentAboutNavigating(content, navigationAware => navigationAware.OnNavigatedToAsync()); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); // REVIEW: I didn't understand something, but why is it necessary? Unloaded += static (sender, _) => { if (sender is NavigationViewContentPresenter navigator) { NotifyContentAboutNavigatingFrom(navigator.Content); } }; } protected override void OnMouseDown(MouseButtonEventArgs e) { if (e.ChangedButton is MouseButton.XButton1 or MouseButton.XButton2) { e.Handled = true; return; } base.OnMouseDown(e); } protected virtual void OnNavigated(NavigationEventArgs eventArgs) { ApplyTransitionEffectToNavigatedPage(eventArgs.Content); if (eventArgs.Content is not DependencyObject dependencyObject) { return; } SetCurrentValue(IsDynamicScrollViewerEnabledProperty, ScrollViewer.GetCanContentScroll(dependencyObject)); } protected virtual void OnNavigating(System.Windows.Navigation.NavigatingCancelEventArgs eventArgs) { NotifyContentAboutNavigatingTo(eventArgs.Content); if (eventArgs.Navigator is not NavigationViewContentPresenter navigator) { return; } NotifyContentAboutNavigatingFrom(navigator.Content); } protected override void OnPreviewKeyDown(KeyEventArgs e) { if (e.Key == Key.F5) { e.Handled = true; return; } base.OnPreviewKeyDown(e); } /// /// Gets or sets a value indicating whether the dynamic scroll viewer is enabled. /// public bool IsDynamicScrollViewerEnabled { get => (bool)GetValue(IsDynamicScrollViewerEnabledProperty); protected set => SetValue(IsDynamicScrollViewerEnabledProperty, value); } /// /// Gets or sets type of transitions during navigation. /// 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); } }