Skip to content

Commit

Permalink
Merge pull request AvaloniaUI#7611 from AvaloniaUI/feature/transition…
Browse files Browse the repository at this point in the history
…ing-content-control

add transitioning content control.
# Conflicts:
#	src/Avalonia.Themes.Default/DefaultTheme.xaml
#	src/Avalonia.Themes.Default/TransitioningContentControl.xaml
  • Loading branch information
jmacato authored and danwalmsley committed Feb 16, 2022
1 parent d22e627 commit 645ce6a
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 0 deletions.
96 changes: 96 additions & 0 deletions src/Avalonia.Controls/TransitioningContentControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Threading;
using Avalonia.Animation;
using Avalonia.Controls.Templates;
using Avalonia.Threading;

namespace Avalonia.Controls;

/// <summary>
/// Displays <see cref="ContentControl.Content"/> according to a <see cref="FuncDataTemplate"/>.
/// Uses <see cref="PageTransition"/> to move between the old and new content values.
/// </summary>
public class TransitioningContentControl : ContentControl
{
private CancellationTokenSource? _lastTransitionCts;
private object? _currentContent;

/// <summary>
/// Defines the <see cref="PageTransition"/> property.
/// </summary>
public static readonly StyledProperty<IPageTransition?> PageTransitionProperty =
AvaloniaProperty.Register<TransitioningContentControl, IPageTransition?>(nameof(PageTransition),
new CrossFade(TimeSpan.FromSeconds(0.125)));

/// <summary>
/// Defines the <see cref="CurrentContent"/> property.
/// </summary>
public static readonly DirectProperty<TransitioningContentControl, object?> CurrentContentProperty =
AvaloniaProperty.RegisterDirect<TransitioningContentControl, object?>(nameof(CurrentContent),
o => o.CurrentContent);

/// <summary>
/// Gets or sets the animation played when content appears and disappears.
/// </summary>
public IPageTransition? PageTransition
{
get => GetValue(PageTransitionProperty);
set => SetValue(PageTransitionProperty, value);
}

/// <summary>
/// Gets the content currently displayed on the screen.
/// </summary>
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<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);

if (change.Property == ContentProperty)
{
Dispatcher.UIThread.Post(() => UpdateContentWithTransition(Content));
}
}

/// <summary>
/// Updates the content with transitions.
/// </summary>
/// <param name="content">New content to set.</param>
private async void UpdateContentWithTransition(object? content)
{
if (VisualRoot is null)
{
return;
}

_lastTransitionCts?.Cancel();
_lastTransitionCts = new CancellationTokenSource();

if (PageTransition != null)
await PageTransition.Start(this, null, true, _lastTransitionCts.Token);

CurrentContent = content;

if (PageTransition != null)
await PageTransition.Start(null, this, true, _lastTransitionCts.Token);
}
}
1 change: 1 addition & 0 deletions src/Avalonia.ReactiveUI/TransitioningContentControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Avalonia.ReactiveUI
/// <summary>
/// A ContentControl that animates the transition when its content is changed.
/// </summary>
[Obsolete("Use TransitioningContentControl in Avalonia.Controls namespace")]
public class TransitioningContentControl : ContentControl, IStyleable
{
/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.Themes.Default/DefaultTheme.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.TabItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TextBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ToggleButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TransitioningContentControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Expander.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TitleBar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TreeView.xaml?assembly=Avalonia.Themes.Default"/>
Expand Down
20 changes: 20 additions & 0 deletions src/Avalonia.Themes.Default/TransitioningContentControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="TransitioningContentControl">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding CurrentContent}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>
</Styles>
1 change: 1 addition & 0 deletions src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TabItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TextBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ToggleButton.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TransitioningContentControl.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Expander.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TitleBar.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TreeView.xaml"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="TransitioningContentControl">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding CurrentContent}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>
</Styles>
2 changes: 2 additions & 0 deletions src/Avalonia.Visuals/Animation/PageSlide.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public async Task Start(Visual from, Visual to, bool forward, CancellationToken
var animation = new Animation
{
Easing = SlideOutEasing,
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
Expand Down Expand Up @@ -109,6 +110,7 @@ public async Task Start(Visual from, Visual to, bool forward, CancellationToken
to.IsVisible = true;
var animation = new Animation
{
FillMode = FillMode.Forward,
Easing = SlideInEasing,
Children =
{
Expand Down

0 comments on commit 645ce6a

Please sign in to comment.