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);
}
}