From 47f3bd759e7b65027fb6e24c4c5a67d91df409b0 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 17:20:49 +0800 Subject: [PATCH 1/7] feat: add control. --- src/Ursa/Controls/BackTop/BackTop.cs | 2 +- src/Ursa/Controls/BackTop/BackTopButton.cs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/Ursa/Controls/BackTop/BackTopButton.cs diff --git a/src/Ursa/Controls/BackTop/BackTop.cs b/src/Ursa/Controls/BackTop/BackTop.cs index 3506807..8a75b49 100644 --- a/src/Ursa/Controls/BackTop/BackTop.cs +++ b/src/Ursa/Controls/BackTop/BackTop.cs @@ -5,7 +5,7 @@ using Avalonia.Media; namespace Ursa.Controls.BackTop; -public class BackTop: Control +public class BackTop : Control { public static readonly AttachedProperty AttachProperty = AvaloniaProperty.RegisterAttached("Attach"); diff --git a/src/Ursa/Controls/BackTop/BackTopButton.cs b/src/Ursa/Controls/BackTop/BackTopButton.cs new file mode 100644 index 0000000..3e035d0 --- /dev/null +++ b/src/Ursa/Controls/BackTop/BackTopButton.cs @@ -0,0 +1,22 @@ +using Avalonia; +using Avalonia.Controls; + +namespace Ursa.Controls; + +public class BackTopButton: Button +{ + public static readonly StyledProperty TargetProperty = AvaloniaProperty.Register( + nameof(Target)); + + public Control Target + { + get => GetValue(TargetProperty); + set => SetValue(TargetProperty, value); + } + + protected override void OnClick() + { + base.OnClick(); + + } +} \ No newline at end of file From 390b581cb813a307a0c12312d28405b132faad88 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 21:07:15 +0800 Subject: [PATCH 2/7] feat: add theme and function. --- demo/Ursa.Demo/Pages/BadgeDemo.axaml | 2 +- .../Controls/ScrollToButton.axaml | 39 ++++++ src/Ursa.Themes.Semi/Controls/_index.axaml | 1 + .../Themes/Shared/ScrollToButton.axaml | 5 + .../Themes/Shared/_index.axaml | 1 + src/Ursa/Controls/BackTop/BackTopButton.cs | 22 ---- src/Ursa/Controls/BackTop/ScrollTo.cs | 64 ++++++++++ src/Ursa/Controls/BackTop/ScrollToButton.cs | 116 ++++++++++++++++++ 8 files changed, 227 insertions(+), 23 deletions(-) create mode 100644 src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml create mode 100644 src/Ursa.Themes.Semi/Themes/Shared/ScrollToButton.axaml delete mode 100644 src/Ursa/Controls/BackTop/BackTopButton.cs create mode 100644 src/Ursa/Controls/BackTop/ScrollTo.cs create mode 100644 src/Ursa/Controls/BackTop/ScrollToButton.cs diff --git a/demo/Ursa.Demo/Pages/BadgeDemo.axaml b/demo/Ursa.Demo/Pages/BadgeDemo.axaml index 012ea37..fda3614 100644 --- a/demo/Ursa.Demo/Pages/BadgeDemo.axaml +++ b/demo/Ursa.Demo/Pages/BadgeDemo.axaml @@ -8,7 +8,7 @@ d:DesignHeight="850" d:DesignWidth="850" mc:Ignorable="d"> - + + + + + + + + + + + + + + + + + + + diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml index 6be2414..ddb53fd 100644 --- a/src/Ursa.Themes.Semi/Controls/_index.axaml +++ b/src/Ursa.Themes.Semi/Controls/_index.axaml @@ -25,6 +25,7 @@ + diff --git a/src/Ursa.Themes.Semi/Themes/Shared/ScrollToButton.axaml b/src/Ursa.Themes.Semi/Themes/Shared/ScrollToButton.axaml new file mode 100644 index 0000000..4e45321 --- /dev/null +++ b/src/Ursa.Themes.Semi/Themes/Shared/ScrollToButton.axaml @@ -0,0 +1,5 @@ + + + M19.637 16.4369C19.0513 17.0227 18.1015 17.0227 17.5157 16.4369L11.8589 10.7801L6.20202 16.4369C5.61623 17.0227 4.66648 17.0227 4.0807 16.4369C3.49491 15.8511 3.49491 14.9014 4.0807 14.3156L10.7982 7.59809C11.384 7.01231 12.3337 7.01231 12.9195 7.59809L19.637 14.3156C20.2228 14.9014 20.2228 15.8511 19.637 16.4369Z + diff --git a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml index 5e43477..b11d979 100644 --- a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml +++ b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml @@ -13,6 +13,7 @@ + diff --git a/src/Ursa/Controls/BackTop/BackTopButton.cs b/src/Ursa/Controls/BackTop/BackTopButton.cs deleted file mode 100644 index 3e035d0..0000000 --- a/src/Ursa/Controls/BackTop/BackTopButton.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Avalonia; -using Avalonia.Controls; - -namespace Ursa.Controls; - -public class BackTopButton: Button -{ - public static readonly StyledProperty TargetProperty = AvaloniaProperty.Register( - nameof(Target)); - - public Control Target - { - get => GetValue(TargetProperty); - set => SetValue(TargetProperty, value); - } - - protected override void OnClick() - { - base.OnClick(); - - } -} \ No newline at end of file diff --git a/src/Ursa/Controls/BackTop/ScrollTo.cs b/src/Ursa/Controls/BackTop/ScrollTo.cs new file mode 100644 index 0000000..09d076c --- /dev/null +++ b/src/Ursa/Controls/BackTop/ScrollTo.cs @@ -0,0 +1,64 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Notifications; +using Avalonia.Controls.Primitives; +using Avalonia.Layout; +using Avalonia.LogicalTree; +using Avalonia.Styling; +using Ursa.Common; + +namespace Ursa.Controls; + +public class ScrollTo +{ + public static readonly AttachedProperty DirectionProperty = + AvaloniaProperty.RegisterAttached("Direction"); + + public static void SetDirection(Control obj, Position value) => obj.SetValue(DirectionProperty, value); + public static Position GetDirection(Control obj) => obj.GetValue(DirectionProperty); + + public static readonly AttachedProperty ButtonThemeProperty = + AvaloniaProperty.RegisterAttached("ButtonTheme"); + + public static void SetButtonTheme(Control obj, ControlTheme? value) => obj.SetValue(ButtonThemeProperty, value); + public static ControlTheme? GetButtonTheme(Control obj) => obj.GetValue(ButtonThemeProperty); + + static ScrollTo() + { + DirectionProperty.Changed.AddClassHandler(OnDirectionChanged); + ButtonThemeProperty.Changed.AddClassHandler(OnButtonThemeChanged); + } + + private static void OnButtonThemeChanged(Control arg1, AvaloniaPropertyChangedEventArgs arg2) + { + var button = EnsureButtonInAdorner(arg1); + if (button is null) return; + button.SetCurrentValue(StyledElement.ThemeProperty, arg2.NewValue.Value); + } + + private static void OnDirectionChanged(Control control, AvaloniaPropertyChangedEventArgs args) + { + var button = EnsureButtonInAdorner(control); + if (button is null) return; + button.SetCurrentValue(ScrollToButton.DirectionProperty, args.NewValue.Value); + } + + private static ScrollToButton? EnsureButtonInAdorner(Control control) + { + var scroll = control.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); + if (scroll is null) return null; + var adorner = AdornerLayer.GetAdorner(scroll); + if (adorner is not ScrollToButton button) + { + button = new ScrollToButton(); + AdornerLayer.SetAdorner(control, button); + } + button.SetCurrentValue(ScrollToButton.TargetProperty, scroll); + button.SetCurrentValue(ScrollToButton.DirectionProperty, GetDirection(control)); + if ( GetButtonTheme(control) is { } theme) + { + button.SetCurrentValue(StyledElement.ThemeProperty, theme); + } + return button; + } +} \ No newline at end of file diff --git a/src/Ursa/Controls/BackTop/ScrollToButton.cs b/src/Ursa/Controls/BackTop/ScrollToButton.cs new file mode 100644 index 0000000..18bb28f --- /dev/null +++ b/src/Ursa/Controls/BackTop/ScrollToButton.cs @@ -0,0 +1,116 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.LogicalTree; +using Irihi.Avalonia.Shared.Helpers; +using Ursa.Common; + +namespace Ursa.Controls; + +public class ScrollToButton: Button +{ + private ScrollViewer? _scroll; + private IDisposable? _disposable; + + public static readonly StyledProperty TargetProperty = AvaloniaProperty.Register( + nameof(Target)); + + public Control Target + { + get => GetValue(TargetProperty); + set => SetValue(TargetProperty, value); + } + + public static readonly StyledProperty DirectionProperty = AvaloniaProperty.Register( + nameof(Direction)); + + public Position Direction + { + get => GetValue(DirectionProperty); + set => SetValue(DirectionProperty, value); + } + + static ScrollToButton() + { + TargetProperty.Changed.AddClassHandler((o,e)=>o.OnTargetChanged(e)); + DirectionProperty.Changed.AddClassHandler((o,e)=>o.OnDirectionChanged(e)); + } + + private void OnDirectionChanged(AvaloniaPropertyChangedEventArgs avaloniaPropertyChangedEventArgs) + { + if (_scroll is null) return; + SetVisibility(avaloniaPropertyChangedEventArgs.NewValue.Value, _scroll.Offset); + } + + private void OnTargetChanged(AvaloniaPropertyChangedEventArgs arg2) + { + _disposable?.Dispose(); + if (arg2.NewValue.Value is { } newValue) + { + var scroll = newValue.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); + if (_scroll is not null) + { + _disposable?.Dispose(); + } + _scroll = scroll; + _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler(OnScrollChanged); + SetVisibility(Direction, _scroll?.Offset); + } + } + + protected override void OnClick() + { + var vector = Direction switch + { + Position.Top => new Vector(0, double.NegativeInfinity), + Position.Bottom => new Vector(0, double.PositiveInfinity), + Position.Left => new Vector(double.NegativeInfinity, 0), + Position.Right => new Vector(double.PositiveInfinity, 0), + _ => new Vector(0, 0) + }; + _scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector); + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + var scroll = Target.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); + if (_scroll is not null) + { + _disposable?.Dispose(); + } + _scroll = scroll; + _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler(OnScrollChanged); + SetVisibility(Direction, _scroll?.Offset); + } + + private void OnScrollChanged(ScrollViewer arg1, AvaloniaPropertyChangedEventArgs arg2) + { + if (arg1 != _scroll) return; + SetVisibility(Direction, arg2.NewValue.Value); + } + + private void SetVisibility(Position direction, Vector? vector) + { + if (vector is null) return; + if (direction == Position.Bottom && vector.Value.Y < 0) + { + IsVisible = true; + } + else if (direction == Position.Top && vector.Value.Y > 0) + { + IsVisible = true; + } + else if (direction == Position.Left && vector.Value.X < 0) + { + IsVisible = true; + } + else if (direction == Position.Right && vector.Value.X > 0) + { + IsVisible = true; + } + else + { + IsVisible = false; + } + } +} \ No newline at end of file From eb14cf9e132cb9b5dd7b594d4c03d2af60628e90 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Wed, 6 Mar 2024 15:46:06 +0800 Subject: [PATCH 3/7] feat: Add theme. --- demo/Ursa.Demo/Models/MenuKeys.cs | 37 --------- demo/Ursa.Demo/Pages/BadgeDemo.axaml | 2 +- demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml | 76 +++++++++++++++++++ .../Pages/ScrollToButtonDemo.axaml.cs | 13 ++++ demo/Ursa.Demo/Ursa.Demo.csproj | 4 + .../Ursa.Demo/ViewModels/MainViewViewModel.cs | 1 + demo/Ursa.Demo/ViewModels/MenuViewModel.cs | 38 ++++++++++ .../ViewModels/ScrollToButtonDemoViewModel.cs | 15 ++++ .../Controls/ScrollToButton.axaml | 11 ++- src/Ursa/Controls/BackTop/ScrollTo.cs | 19 ++--- src/Ursa/Controls/BackTop/ScrollToButton.cs | 22 +++--- 11 files changed, 181 insertions(+), 57 deletions(-) delete mode 100644 demo/Ursa.Demo/Models/MenuKeys.cs create mode 100644 demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml create mode 100644 demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml.cs create mode 100644 demo/Ursa.Demo/ViewModels/ScrollToButtonDemoViewModel.cs diff --git a/demo/Ursa.Demo/Models/MenuKeys.cs b/demo/Ursa.Demo/Models/MenuKeys.cs deleted file mode 100644 index b7b1a76..0000000 --- a/demo/Ursa.Demo/Models/MenuKeys.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Ursa.Demo; - -public static class MenuKeys -{ - public const string MenuKeyIntroduction = "Introduction"; - public const string MenuKeyBadge = "Badge"; - public const string MenuKeyBanner = "Banner"; - public const string MenuKeyButtonGroup = "ButtonGroup"; - public const string MenuKeyBreadcrumb = "Breadcrumb"; - public const string MenuKeyClassInput = "Class Input"; - public const string MenuKeyDialog = "Dialog"; - public const string MenuKeyDivider = "Divider"; - public const string MenuKeyDisableContainer = "DisableContainer"; - public const string MenuKeyDrawer = "Drawer"; - public const string MenuKeyDualBadge = "DualBadge"; - public const string MenuKeyEnumSelector = "EnumSelector"; - public const string MenuKeyForm = "Form"; - public const string MenuKeyImageViewer = "ImageViewer"; - public const string MenuKeyIpBox = "IPv4Box"; - public const string MenuKeyIconButton = "IconButton"; - public const string MenuKeyKeyGestureInput = "KeyGestureInput"; - public const string MenuKeyLoading = "Loading"; - public const string MenuKeyMessageBox = "MessageBox"; - public const string MenuKeyNavMenu = "NavMenu"; - public const string MenuKeyNumberDisplayer = "NumberDisplayer"; - public const string MenuKeyNumericUpDown = "NumericUpDown"; - public const string MenuKeyPagination = "Pagination"; - public const string MenuKeyRangeSlider = "RangeSlider"; - public const string MenuKeySelectionList = "SelectionList"; - public const string MenuKeyTagInput = "TagInput"; - public const string MenuKeySkeleton = "Skeleton"; - public const string MenuKeyTimeline = "Timeline"; - public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon"; - public const string MenuKeyThemeToggler = "ThemeToggler"; - public const string MenuKeyToolBar = "ToolBar"; - -} \ No newline at end of file diff --git a/demo/Ursa.Demo/Pages/BadgeDemo.axaml b/demo/Ursa.Demo/Pages/BadgeDemo.axaml index fda3614..f46673b 100644 --- a/demo/Ursa.Demo/Pages/BadgeDemo.axaml +++ b/demo/Ursa.Demo/Pages/BadgeDemo.axaml @@ -8,7 +8,7 @@ d:DesignHeight="850" d:DesignWidth="850" mc:Ignorable="d"> - + + + + + + + Scroll To Top + Scroll To Bottom + Scroll To Left + Scroll To Right + Scroll To Top + + + + + + + + + + + + + + + diff --git a/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml.cs b/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml.cs new file mode 100644 index 0000000..5e7741c --- /dev/null +++ b/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Ursa.Demo.Pages; + +public partial class ScrollToButtonDemo : UserControl +{ + public ScrollToButtonDemo() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/demo/Ursa.Demo/Ursa.Demo.csproj b/demo/Ursa.Demo/Ursa.Demo.csproj index cdf1e1b..92d7e39 100644 --- a/demo/Ursa.Demo/Ursa.Demo.csproj +++ b/demo/Ursa.Demo/Ursa.Demo.csproj @@ -32,4 +32,8 @@ SkeletonDemo.axaml + + + + diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs index d987128..5a0cd77 100644 --- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs @@ -48,6 +48,7 @@ public class MainViewViewModel : ViewModelBase MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(), MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(), MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(), + MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(), MenuKeys.MenuKeySelectionList => new SelectionListDemoViewModel(), MenuKeys.MenuKeySkeleton => new SkeletonDemoViewModel(), MenuKeys.MenuKeyTagInput => new TagInputDemoViewModel(), diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs index a4eaa14..b500267 100644 --- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs @@ -35,6 +35,7 @@ public class MenuViewModel: ViewModelBase new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown }, new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination }, new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider }, + new() { MenuHeader = "ScrollToButton", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" }, new() { MenuHeader = "Selection List", Key = MenuKeys.MenuKeySelectionList, Status = "New" }, new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton, Status = "New" }, new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput }, @@ -44,4 +45,41 @@ public class MenuViewModel: ViewModelBase new() { MenuHeader = "ToolBar", Key = MenuKeys.MenuKeyToolBar, Status = "New" } }; } +} + +public static class MenuKeys +{ + public const string MenuKeyIntroduction = "Introduction"; + public const string MenuKeyBadge = "Badge"; + public const string MenuKeyBanner = "Banner"; + public const string MenuKeyButtonGroup = "ButtonGroup"; + public const string MenuKeyBreadcrumb= "Breadcrumb"; + public const string MenuKeyClassInput = "Class Input"; + public const string MenuKeyDialog = "Dialog"; + public const string MenuKeyDivider = "Divider"; + public const string MenuKeyDisableContainer = "DisableContainer"; + public const string MenuKeyDrawer = "Drawer"; + public const string MenuKeyDualBadge = "DualBadge"; + public const string MenuKeyEnumSelector = "EnumSelector"; + public const string MenuKeyForm = "Form"; + public const string MenuKeyImageViewer = "ImageViewer"; + public const string MenuKeyIpBox = "IPv4Box"; + public const string MenuKeyIconButton = "IconButton"; + public const string MenuKeyKeyGestureInput = "KeyGestureInput"; + public const string MenuKeyLoading = "Loading"; + public const string MenuKeyMessageBox = "MessageBox"; + public const string MenuKeyNavMenu = "NavMenu"; + public const string MenuKeyNumberDisplayer = "NumberDisplayer"; + public const string MenuKeyNumericUpDown = "NumericUpDown"; + public const string MenuKeyPagination = "Pagination"; + public const string MenuKeyRangeSlider = "RangeSlider"; + public const string MenuKeyScrollToButton = "ScrollToButton"; + public const string MenuKeySelectionList = "SelectionList"; + public const string MenuKeyTagInput = "TagInput"; + public const string MenuKeySkeleton = "Skeleton"; + public const string MenuKeyTimeline = "Timeline"; + public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon"; + public const string MenuKeyThemeToggler = "ThemeToggler"; + public const string MenuKeyToolBar = "ToolBar"; + } \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/ScrollToButtonDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/ScrollToButtonDemoViewModel.cs new file mode 100644 index 0000000..833189f --- /dev/null +++ b/demo/Ursa.Demo/ViewModels/ScrollToButtonDemoViewModel.cs @@ -0,0 +1,15 @@ +using System.Collections.ObjectModel; +using System.Linq; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Ursa.Demo.ViewModels; + +public class ScrollToButtonDemoViewModel: ObservableObject +{ + public ObservableCollection Items { get; set; } + + public ScrollToButtonDemoViewModel() + { + Items = new ObservableCollection(Enumerable.Range(0, 1000).Select(a => "Item " + a)); + } +} \ No newline at end of file diff --git a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml index 22816d8..02a00fe 100644 --- a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml +++ b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml @@ -7,7 +7,7 @@ - + + + + diff --git a/src/Ursa/Controls/BackTop/ScrollTo.cs b/src/Ursa/Controls/BackTop/ScrollTo.cs index 09d076c..1f20340 100644 --- a/src/Ursa/Controls/BackTop/ScrollTo.cs +++ b/src/Ursa/Controls/BackTop/ScrollTo.cs @@ -2,20 +2,22 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Notifications; using Avalonia.Controls.Primitives; +using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.LogicalTree; using Avalonia.Styling; +using Avalonia.VisualTree; using Ursa.Common; namespace Ursa.Controls; public class ScrollTo { - public static readonly AttachedProperty DirectionProperty = - AvaloniaProperty.RegisterAttached("Direction"); + public static readonly AttachedProperty DirectionProperty = + AvaloniaProperty.RegisterAttached("Direction"); public static void SetDirection(Control obj, Position value) => obj.SetValue(DirectionProperty, value); - public static Position GetDirection(Control obj) => obj.GetValue(DirectionProperty); + public static Position? GetDirection(Control obj) => obj.GetValue(DirectionProperty); public static readonly AttachedProperty ButtonThemeProperty = AvaloniaProperty.RegisterAttached("ButtonTheme"); @@ -25,7 +27,7 @@ public class ScrollTo static ScrollTo() { - DirectionProperty.Changed.AddClassHandler(OnDirectionChanged); + DirectionProperty.Changed.AddClassHandler(OnDirectionChanged); ButtonThemeProperty.Changed.AddClassHandler(OnButtonThemeChanged); } @@ -36,8 +38,9 @@ public class ScrollTo button.SetCurrentValue(StyledElement.ThemeProperty, arg2.NewValue.Value); } - private static void OnDirectionChanged(Control control, AvaloniaPropertyChangedEventArgs args) + private static void OnDirectionChanged(Control control, AvaloniaPropertyChangedEventArgs args) { + if (args.NewValue.Value is null) return; var button = EnsureButtonInAdorner(control); if (button is null) return; button.SetCurrentValue(ScrollToButton.DirectionProperty, args.NewValue.Value); @@ -45,15 +48,13 @@ public class ScrollTo private static ScrollToButton? EnsureButtonInAdorner(Control control) { - var scroll = control.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); - if (scroll is null) return null; - var adorner = AdornerLayer.GetAdorner(scroll); + var adorner = AdornerLayer.GetAdorner(control); if (adorner is not ScrollToButton button) { button = new ScrollToButton(); AdornerLayer.SetAdorner(control, button); } - button.SetCurrentValue(ScrollToButton.TargetProperty, scroll); + button.SetCurrentValue(ScrollToButton.TargetProperty, control); button.SetCurrentValue(ScrollToButton.DirectionProperty, GetDirection(control)); if ( GetButtonTheme(control) is { } theme) { diff --git a/src/Ursa/Controls/BackTop/ScrollToButton.cs b/src/Ursa/Controls/BackTop/ScrollToButton.cs index 18bb28f..4d85d0e 100644 --- a/src/Ursa/Controls/BackTop/ScrollToButton.cs +++ b/src/Ursa/Controls/BackTop/ScrollToButton.cs @@ -1,6 +1,8 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Interactivity; using Avalonia.LogicalTree; +using Avalonia.VisualTree; using Irihi.Avalonia.Shared.Helpers; using Ursa.Common; @@ -46,10 +48,11 @@ public class ScrollToButton: Button _disposable?.Dispose(); if (arg2.NewValue.Value is { } newValue) { - var scroll = newValue.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); + var scroll = newValue.GetSelfAndVisualDescendants().OfType().FirstOrDefault(); if (_scroll is not null) { _disposable?.Dispose(); + _scroll = null; } _scroll = scroll; _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler(OnScrollChanged); @@ -69,14 +72,15 @@ public class ScrollToButton: Button }; _scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector); } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + + protected override void OnLoaded(RoutedEventArgs e) { - base.OnAttachedToVisualTree(e); - var scroll = Target.GetSelfAndLogicalDescendants().OfType().FirstOrDefault(); + base.OnLoaded(e); + var scroll = Target.GetSelfAndVisualDescendants().OfType().FirstOrDefault(); if (_scroll is not null) { _disposable?.Dispose(); + _scroll = null; } _scroll = scroll; _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler(OnScrollChanged); @@ -91,8 +95,8 @@ public class ScrollToButton: Button private void SetVisibility(Position direction, Vector? vector) { - if (vector is null) return; - if (direction == Position.Bottom && vector.Value.Y < 0) + if (vector is null || _scroll is null) return; + if (direction == Position.Bottom && vector.Value.Y < _scroll.Extent.Height - _scroll.Bounds.Height) { IsVisible = true; } @@ -100,11 +104,11 @@ public class ScrollToButton: Button { IsVisible = true; } - else if (direction == Position.Left && vector.Value.X < 0) + else if (direction == Position.Left && vector.Value.X > 0) { IsVisible = true; } - else if (direction == Position.Right && vector.Value.X > 0) + else if (direction == Position.Right && vector.Value.X < _scroll.Extent.Width - _scroll.Bounds.Width) { IsVisible = true; } From a85f948f791906bd2f1ccf03cc21b06219fbab82 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 22:01:13 +0800 Subject: [PATCH 4/7] misc: fix demo name. --- demo/Ursa.Demo/ViewModels/MenuViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs index b500267..a48238e 100644 --- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs @@ -35,7 +35,7 @@ public class MenuViewModel: ViewModelBase new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown }, new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination }, new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider }, - new() { MenuHeader = "ScrollToButton", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" }, + new() { MenuHeader = "Scroll To", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" }, new() { MenuHeader = "Selection List", Key = MenuKeys.MenuKeySelectionList, Status = "New" }, new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton, Status = "New" }, new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput }, From cedbafb9189bc818f008b38742c2ad90d93946e1 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Wed, 6 Mar 2024 16:14:27 +0800 Subject: [PATCH 5/7] fix: fix file name error. --- src/Ursa/Controls/BackTop/BackTop.cs | 15 --------------- .../Controls/{BackTop => ScrollTo}/ScrollTo.cs | 5 ----- .../{BackTop => ScrollTo}/ScrollToButton.cs | 9 +++++++-- 3 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 src/Ursa/Controls/BackTop/BackTop.cs rename src/Ursa/Controls/{BackTop => ScrollTo}/ScrollTo.cs (94%) rename src/Ursa/Controls/{BackTop => ScrollTo}/ScrollToButton.cs (94%) diff --git a/src/Ursa/Controls/BackTop/BackTop.cs b/src/Ursa/Controls/BackTop/BackTop.cs deleted file mode 100644 index 8a75b49..0000000 --- a/src/Ursa/Controls/BackTop/BackTop.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Media; - -namespace Ursa.Controls.BackTop; - -public class BackTop : Control -{ - public static readonly AttachedProperty AttachProperty = - AvaloniaProperty.RegisterAttached("Attach"); - - public static void SetAttach(Control obj, bool value) => obj.SetValue(AttachProperty, value); - public static bool GetAttach(Control obj) => obj.GetValue(AttachProperty); -} \ No newline at end of file diff --git a/src/Ursa/Controls/BackTop/ScrollTo.cs b/src/Ursa/Controls/ScrollTo/ScrollTo.cs similarity index 94% rename from src/Ursa/Controls/BackTop/ScrollTo.cs rename to src/Ursa/Controls/ScrollTo/ScrollTo.cs index 1f20340..fc1dcfb 100644 --- a/src/Ursa/Controls/BackTop/ScrollTo.cs +++ b/src/Ursa/Controls/ScrollTo/ScrollTo.cs @@ -1,12 +1,7 @@ using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Notifications; using Avalonia.Controls.Primitives; -using Avalonia.Interactivity; -using Avalonia.Layout; -using Avalonia.LogicalTree; using Avalonia.Styling; -using Avalonia.VisualTree; using Ursa.Common; namespace Ursa.Controls; diff --git a/src/Ursa/Controls/BackTop/ScrollToButton.cs b/src/Ursa/Controls/ScrollTo/ScrollToButton.cs similarity index 94% rename from src/Ursa/Controls/BackTop/ScrollToButton.cs rename to src/Ursa/Controls/ScrollTo/ScrollToButton.cs index 4d85d0e..51a1df3 100644 --- a/src/Ursa/Controls/BackTop/ScrollToButton.cs +++ b/src/Ursa/Controls/ScrollTo/ScrollToButton.cs @@ -1,7 +1,10 @@ using Avalonia; +using Avalonia.Animation; +using Avalonia.Animation.Easings; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.LogicalTree; +using Avalonia.Styling; using Avalonia.VisualTree; using Irihi.Avalonia.Shared.Helpers; using Ursa.Common; @@ -55,13 +58,15 @@ public class ScrollToButton: Button _scroll = null; } _scroll = scroll; + _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler(OnScrollChanged); SetVisibility(Direction, _scroll?.Offset); } } - protected override void OnClick() + protected override async void OnClick() { + if (_scroll is null) return; var vector = Direction switch { Position.Top => new Vector(0, double.NegativeInfinity), @@ -70,7 +75,7 @@ public class ScrollToButton: Button Position.Right => new Vector(double.PositiveInfinity, 0), _ => new Vector(0, 0) }; - _scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector); + _scroll.SetCurrentValue(ScrollViewer.OffsetProperty, vector); } protected override void OnLoaded(RoutedEventArgs e) From 9c5dd0d05508ebbee5b5d49d32a581fa946c1b7a Mon Sep 17 00:00:00 2001 From: rabbitism Date: Wed, 6 Mar 2024 16:59:59 +0800 Subject: [PATCH 6/7] feat: fix icon size. (I don't know the reason thou) --- src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml index 02a00fe..666b51c 100644 --- a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml +++ b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml @@ -17,8 +17,8 @@ From 0881b57a1d9448ddac423ccc50e2d66452eb2f13 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Wed, 6 Mar 2024 17:06:42 +0800 Subject: [PATCH 7/7] feat: add default solid theme. --- demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml | 1 + .../Controls/ScrollToButton.axaml | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml b/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml index 77be78e..a7022e3 100644 --- a/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml +++ b/demo/Ursa.Demo/Pages/ScrollToButtonDemo.axaml @@ -69,6 +69,7 @@ Grid.Row="1" Grid.Column="4" u:ScrollTo.Direction="Top" + u:ScrollTo.ButtonTheme="{DynamicResource PrimaryScrollToButton}" ItemsSource="{Binding Items}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" /> diff --git a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml index 666b51c..dc205d0 100644 --- a/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml +++ b/src/Ursa.Themes.Semi/Controls/ScrollToButton.axaml @@ -45,4 +45,48 @@ + + + + + + + + + + + + + + + + + + + + +