Files
Shrlalgo.RvKits/WPFluent/Controls/NavigationView/NavigationViewContentPresenter.cs
2025-04-24 20:56:44 +08:00

220 lines
6.9 KiB
C#

/* 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
{
/// <summary>
/// Identifies the <see cref="IsDynamicScrollViewerEnabled"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsDynamicScrollViewerEnabledProperty =
DependencyProperty.Register(
nameof(IsDynamicScrollViewerEnabled),
typeof(bool),
typeof(NavigationViewContentPresenter),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <see cref="TransitionDuration"/> dependency property.
/// </summary>
public static readonly DependencyProperty TransitionDurationProperty = DependencyProperty.Register(
nameof(TransitionDuration),
typeof(int),
typeof(NavigationViewContentPresenter),
new FrameworkPropertyMetadata(200));
/// <summary>
/// Identifies the <see cref="Transition"/> dependency property.
/// </summary>
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<INavigationAware, Task> 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<object> { 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);
}
/// <summary>
/// Gets or sets a value indicating whether the dynamic scroll viewer is enabled.
/// </summary>
public bool IsDynamicScrollViewerEnabled
{
get => (bool)GetValue(IsDynamicScrollViewerEnabledProperty);
protected set => SetValue(IsDynamicScrollViewerEnabledProperty, value);
}
/// <summary>
/// Gets or sets type of <see cref="NavigationViewContentPresenter"/> transitions during navigation.
/// </summary>
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);
}
}