From bb7873ef66df2206df10be0f886d418e0c62fe1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9B=E5=B0=98=E7=A9=BA=E5=BF=A7?= Date: Sat, 9 Aug 2025 23:00:15 +0800 Subject: [PATCH 1/6] feat:Implements subtle animations for the NavMenu in a non-intrusive way. --- demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs | 11 +++ .../Controls/NavMenu/WHAnimationHelper.cs | 78 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/Ursa/Controls/NavMenu/WHAnimationHelper.cs diff --git a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs index 6e78ad8..ec9ec24 100644 --- a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs +++ b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs @@ -1,11 +1,22 @@ using Avalonia.Controls; +using Avalonia.Interactivity; +using Ursa.Controls; namespace Ursa.Demo.Pages; public partial class NavMenuDemo : UserControl { + private readonly WHAnimationHelper _animationHelper; + public NavMenuDemo() { InitializeComponent(); + _animationHelper = new WHAnimationHelper(menu, NavMenu.IsHorizontalCollapsedProperty); + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + _animationHelper.Start(); } } \ No newline at end of file diff --git a/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs b/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs new file mode 100644 index 0000000..649a8d6 --- /dev/null +++ b/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs @@ -0,0 +1,78 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Styling; +using Avalonia.Threading; +using Avalonia.VisualTree; + +namespace Ursa.Controls; + +public class WHAnimationHelper(Control control, AvaloniaProperty property) +{ + private CancellationTokenSource? _cancellationTokenSource; + + ~WHAnimationHelper() + { + _cancellationTokenSource?.Dispose(); + } + + public void Stop() + { + control.PropertyChanged -= AnimationTargetOnPropertyChanged; + } + + public void Start() + { + control.PropertyChanged += AnimationTargetOnPropertyChanged; + } + + private void AnimationTargetOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (sender as Control != control || + e.Property != property || + control.IsLoaded is false || + control.IsVisible is false) return; + _cancellationTokenSource?.Cancel(); + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = new CancellationTokenSource(); + + var oldValue = control.DesiredSize; + control.UpdateLayout(); + var newValue = control.DesiredSize; + newValue = newValue.WithWidth(newValue.Width + 20); + control.InvalidateArrange(); + var animation = CreateAnimation(oldValue, newValue); + animation.RunAsync(control, _cancellationTokenSource.Token); + } + + protected virtual Animation CreateAnimation(Size oldValue, Size newValue) + { + return new Animation + { + Duration = TimeSpan.FromMilliseconds(300), + Easing = new CubicEaseInOut(), + FillMode = FillMode.None, + Children = + { + new KeyFrame + { + Cue = new Cue(0.0), + Setters = + { + new Setter(Layoutable.WidthProperty, oldValue.Width) + } + }, + new KeyFrame + { + Cue = new Cue(1.0), + Setters = + { + new Setter(Layoutable.WidthProperty, newValue.Width) + } + } + } + }; + } +} \ No newline at end of file From c801c4eec4804a5c8e585e7e94b00276687ef74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9B=E5=B0=98=E7=A9=BA=E5=BF=A7?= Date: Sun, 10 Aug 2025 00:00:30 +0800 Subject: [PATCH 2/6] misc:Refactor the WHAnimationHelper class structure to clearly define its responsibilities. --- demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs | 5 +- src/Ursa/Helpers/NavMenuAnimationHelper.cs | 46 +++++++++++++++++++ .../NavMenu => Helpers}/WHAnimationHelper.cs | 3 +- 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 src/Ursa/Helpers/NavMenuAnimationHelper.cs rename src/Ursa/{Controls/NavMenu => Helpers}/WHAnimationHelper.cs (96%) diff --git a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs index ec9ec24..aff3e1b 100644 --- a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs +++ b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs @@ -1,17 +1,18 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Ursa.Controls; +using Ursa.Helpers; namespace Ursa.Demo.Pages; public partial class NavMenuDemo : UserControl { - private readonly WHAnimationHelper _animationHelper; + private readonly NavMenuAnimationHelper _animationHelper; public NavMenuDemo() { InitializeComponent(); - _animationHelper = new WHAnimationHelper(menu, NavMenu.IsHorizontalCollapsedProperty); + _animationHelper = new NavMenuAnimationHelper(menu); } protected override void OnLoaded(RoutedEventArgs e) diff --git a/src/Ursa/Helpers/NavMenuAnimationHelper.cs b/src/Ursa/Helpers/NavMenuAnimationHelper.cs new file mode 100644 index 0000000..5848792 --- /dev/null +++ b/src/Ursa/Helpers/NavMenuAnimationHelper.cs @@ -0,0 +1,46 @@ +using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; +using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Styling; +using Ursa.Controls; + +namespace Ursa.Helpers; + +public class NavMenuAnimationHelper(NavMenu control) : WHAnimationHelper(control, NavMenu.IsHorizontalCollapsedProperty) +{ + protected override Animation CreateAnimation(Size oldValue, Size newValue) + { + if (oldValue.Width > newValue.Width) + { + newValue = newValue.WithWidth(newValue.Width + 20); + } + + return new Animation + { + Duration = TimeSpan.FromMilliseconds(300), + Easing = new CubicEaseInOut(), + FillMode = FillMode.None, + Children = + { + new KeyFrame + { + Cue = new Cue(0.0), + Setters = + { + new Setter(Layoutable.WidthProperty, oldValue.Width) + } + }, + new KeyFrame + { + Cue = new Cue(1.0), + Setters = + { + new Setter(Layoutable.WidthProperty, newValue.Width) + } + } + } + }; + } +} \ No newline at end of file diff --git a/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs b/src/Ursa/Helpers/WHAnimationHelper.cs similarity index 96% rename from src/Ursa/Controls/NavMenu/WHAnimationHelper.cs rename to src/Ursa/Helpers/WHAnimationHelper.cs index 649a8d6..d583b3c 100644 --- a/src/Ursa/Controls/NavMenu/WHAnimationHelper.cs +++ b/src/Ursa/Helpers/WHAnimationHelper.cs @@ -7,7 +7,7 @@ using Avalonia.Styling; using Avalonia.Threading; using Avalonia.VisualTree; -namespace Ursa.Controls; +namespace Ursa.Helpers; public class WHAnimationHelper(Control control, AvaloniaProperty property) { @@ -41,7 +41,6 @@ public class WHAnimationHelper(Control control, AvaloniaProperty property) var oldValue = control.DesiredSize; control.UpdateLayout(); var newValue = control.DesiredSize; - newValue = newValue.WithWidth(newValue.Width + 20); control.InvalidateArrange(); var animation = CreateAnimation(oldValue, newValue); animation.RunAsync(control, _cancellationTokenSource.Token); From b9e104a8b82ec3edbded1f4284c3800910045efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9B=E5=B0=98=E7=A9=BA=E5=BF=A7?= Date: Sun, 10 Aug 2025 16:37:03 +0800 Subject: [PATCH 3/6] feat:Redesign the usage pattern of WHAnimationHelper once more to deliver a superior axaml editing and consumption experience. --- demo/Ursa.Demo/Pages/NavMenuDemo.axaml | 6 +- demo/Ursa.Demo/Pages/NavMenuDemo.axaml.cs | 49 +++++-- src/Ursa/Helpers/NavMenuAnimationHelper.cs | 46 ------- src/Ursa/Helpers/WHAnimationHelper.cs | 152 ++++++++++++++++----- 4 files changed, 160 insertions(+), 93 deletions(-) delete mode 100644 src/Ursa/Helpers/NavMenuAnimationHelper.cs diff --git a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml index 424e03a..81d75cf 100644 --- a/demo/Ursa.Demo/Pages/NavMenuDemo.axaml +++ b/demo/Ursa.Demo/Pages/NavMenuDemo.axaml @@ -8,6 +8,7 @@ xmlns:u="https://irihi.tech/ursa" xmlns:vm="using:Ursa.Demo.ViewModels" xmlns:iri="https://irihi.tech/shared" + xmlns:views="using:Ursa.Demo.Pages" d:DesignHeight="450" d:DesignWidth="800" x:CompileBindings="True" @@ -39,7 +40,10 @@ IsHorizontalCollapsed="{Binding #collapse.IsChecked, Mode=OneWay}" ItemsSource="{Binding MenuItems}" SelectedItem="{Binding SelectedMenuItem}" - SubMenuBinding="{Binding Children}"> + SubMenuBinding="{Binding Children}" + u:WHAnimationHelper.TriggerAvaloniaProperty="{x:Static u:NavMenu.IsHorizontalCollapsedProperty}" + u:WHAnimationHelper.CreateAnimation="{x:Static views:NavMenuDemo.NavMenuAnimation}" + u:WHAnimationHelper.EnableWHAnimation="True"> - - - - - - + + + + + + + + + @@ -44,6 +44,15 @@ + @@ -134,13 +143,15 @@ - + - + @@ -183,12 +194,12 @@ - - + +