using System; using System.Threading; using Avalonia.Animation; using Avalonia.Controls.Templates; using Avalonia.Threading; namespace Avalonia.Controls; /// /// Displays according to a . /// Uses to move between the old and new content values. /// public class TransitioningContentControl : ContentControl { private CancellationTokenSource? _lastTransitionCts; private object? _currentContent; /// /// Defines the property. /// public static readonly StyledProperty PageTransitionProperty = AvaloniaProperty.Register(nameof(PageTransition), new CrossFade(TimeSpan.FromSeconds(0.125))); /// /// Defines the property. /// public static readonly DirectProperty CurrentContentProperty = AvaloniaProperty.RegisterDirect(nameof(CurrentContent), o => o.CurrentContent); /// /// Gets or sets the animation played when content appears and disappears. /// public IPageTransition? PageTransition { get => GetValue(PageTransitionProperty); set => SetValue(PageTransitionProperty, value); } /// /// Gets the content currently displayed on the screen. /// public object? CurrentContent { get => _currentContent; private set => SetAndRaise(CurrentContentProperty, ref _currentContent, value); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); Dispatcher.UIThread.Post(() => UpdateContentWithTransition(Content)); } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); _lastTransitionCts?.Cancel(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == ContentProperty) { Dispatcher.UIThread.Post(() => UpdateContentWithTransition(Content)); } else if (change.Property == CurrentContentProperty) { UpdateLogicalTree(change.OldValue, change.NewValue); } } protected override void ContentChanged(AvaloniaPropertyChangedEventArgs e) { // We do nothing becuse we should not remove old Content until the animation is over } /// /// Updates the content with transitions. /// /// New content to set. private async void UpdateContentWithTransition(object? content) { if (VisualRoot is null) { return; } _lastTransitionCts?.Cancel(); _lastTransitionCts = new CancellationTokenSource(); var localToken = _lastTransitionCts.Token; if (PageTransition != null) await PageTransition.Start(this, null, true, localToken); if (localToken.IsCancellationRequested) { return; } CurrentContent = content; if (PageTransition != null) await PageTransition.Start(null, this, true, localToken); } }