From 2af11dea7ebf3c248cc5fc44c75449d0552e3d2d Mon Sep 17 00:00:00 2001 From: rabbitism Date: Thu, 29 Feb 2024 23:45:44 +0800 Subject: [PATCH 1/9] feat: initialize breadcrumb. --- src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 85 +++++++++++++++++++ .../Controls/Breadcrumb/BreadcrumbItem.cs | 41 +++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/Ursa/Controls/Breadcrumb/Breadcrumb.cs create mode 100644 src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs new file mode 100644 index 0000000..d2ab31c --- /dev/null +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -0,0 +1,85 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Data; +using Avalonia.Layout; +using Avalonia.Metadata; + +namespace Ursa.Controls; + +public class Breadcrumb: ItemsControl +{ + private static readonly ITemplate _defaultPanel = + new FuncTemplate(() => new StackPanel() { Orientation = Orientation.Horizontal }); + + + public static readonly StyledProperty IconBindingProperty = AvaloniaProperty.Register( + nameof(IconBinding)); + + [AssignBinding] + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IBinding? IconBinding + { + get => GetValue(IconBindingProperty); + set => SetValue(IconBindingProperty, value); + } + + public static readonly StyledProperty CommandBindingProperty = AvaloniaProperty.Register( + nameof(CommandBinding)); + + [AssignBinding] + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IBinding? CommandBinding + { + get => GetValue(CommandBindingProperty); + set => SetValue(CommandBindingProperty, value); + } + + public static readonly StyledProperty SeparatorProperty = AvaloniaProperty.Register( + nameof(Separator)); + + /// + /// Separator between items. + /// Usage: Separator can only be raw string or ITemplate<Control>. + /// + public object? Separator + { + get => GetValue(SeparatorProperty); + set => SetValue(SeparatorProperty, value); + } + + static Breadcrumb() + { + ItemsPanelProperty.OverrideDefaultValue(_defaultPanel); + } + + protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) + { + return NeedsContainer(item, out recycleKey); + } + + protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) + { + return new BreadcrumbItem(); + } + + protected override void PrepareContainerForItemOverride(Control container, object? item, int index) + { + base.PrepareContainerForItemOverride(container, item, index); + if (container is BreadcrumbItem breadcrumbItem) + { + if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) + { + SeparatorProperty.Changed.AddClassHandler((o, e) => + { + breadcrumbItem.Separator = e.NewValue.Value switch + { + string s => s, + ITemplate t => t.Build(), + _ => e.NewValue.Value?.ToString() + }; + }); + } + } + } +} \ No newline at end of file diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs new file mode 100644 index 0000000..1de6be1 --- /dev/null +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -0,0 +1,41 @@ +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; + +namespace Ursa.Controls; + +public class BreadcrumbItem: ContentControl +{ + public static readonly StyledProperty SeparatorProperty = + AvaloniaProperty.Register( + nameof(Separator), "/"); + + public object? Separator + { + get => GetValue(SeparatorProperty); + set => SetValue(SeparatorProperty, value); + } + + public static readonly StyledProperty IconProperty = AvaloniaProperty.Register( + nameof(Icon)); + + public object? Icon + { + get => GetValue(IconProperty); + set => SetValue(IconProperty, value); + } + + public static readonly StyledProperty CommandProperty = AvaloniaProperty.Register( + nameof(Command)); + + public ICommand? Command + { + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + static BreadcrumbItem() + { + + } +} \ No newline at end of file From 4d1d45579a64221930327ea1220797a9b4a912b0 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Fri, 1 Mar 2024 00:12:19 +0800 Subject: [PATCH 2/9] feat: add demo. --- demo/Ursa.Demo/Models/MenuKeys.cs | 1 + demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 15 ++++++++ demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml.cs | 13 +++++++ .../ViewModels/BreadcrumbDemoViewModel.cs | 8 +++++ .../Ursa.Demo/ViewModels/MainViewViewModel.cs | 1 + demo/Ursa.Demo/ViewModels/MenuViewModel.cs | 1 + .../Controls/Breadcrumb.axaml | 25 +++++++++++++ src/Ursa.Themes.Semi/Controls/_index.axaml | 1 + src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 35 +++++++++++++------ .../Controls/Breadcrumb/BreadcrumbItem.cs | 10 ++++++ 10 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml create mode 100644 demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml.cs create mode 100644 demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs create mode 100644 src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml diff --git a/demo/Ursa.Demo/Models/MenuKeys.cs b/demo/Ursa.Demo/Models/MenuKeys.cs index 085be94..b7b1a76 100644 --- a/demo/Ursa.Demo/Models/MenuKeys.cs +++ b/demo/Ursa.Demo/Models/MenuKeys.cs @@ -6,6 +6,7 @@ public static class MenuKeys 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"; diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml new file mode 100644 index 0000000..ac75e8b --- /dev/null +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml.cs b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml.cs new file mode 100644 index 0000000..c119fc7 --- /dev/null +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Ursa.Demo.Pages; + +public partial class BreadcrumbDemo : UserControl +{ + public BreadcrumbDemo() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs new file mode 100644 index 0000000..92f716a --- /dev/null +++ b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs @@ -0,0 +1,8 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Ursa.Demo.ViewModels; + +public class BreadcrumbDemoViewModel: ObservableObject +{ + +} \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs index 8cc13e6..d987128 100644 --- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs @@ -28,6 +28,7 @@ public class MainViewViewModel : ViewModelBase MenuKeys.MenuKeyBadge => new BadgeDemoViewModel(), MenuKeys.MenuKeyBanner => new BannerDemoViewModel(), MenuKeys.MenuKeyButtonGroup => new ButtonGroupDemoViewModel(), + MenuKeys.MenuKeyBreadcrumb => new BreadcrumbDemoViewModel(), MenuKeys.MenuKeyClassInput => new ClassInputDemoViewModel(), MenuKeys.MenuKeyDialog => new DialogDemoViewModel(), MenuKeys.MenuKeyDivider => new DividerDemoViewModel(), diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs index a25e8d1..a4eaa14 100644 --- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs @@ -14,6 +14,7 @@ public class MenuViewModel: ViewModelBase new() { MenuHeader = "Controls", IsSeparator = true }, new() { MenuHeader = "Badge", Key = MenuKeys.MenuKeyBadge, Status = "Updated"}, new() { MenuHeader = "Banner", Key = MenuKeys.MenuKeyBanner }, + new() { MenuHeader = "Breadcrumb", Key = MenuKeys.MenuKeyBreadcrumb, Status = "New" }, new() { MenuHeader = "Button Group", Key = MenuKeys.MenuKeyButtonGroup}, new() { MenuHeader = "Class Input", Key = MenuKeys.MenuKeyClassInput, Status = "New" }, new() { MenuHeader = "Dialog", Key = MenuKeys.MenuKeyDialog, Status = "Updated"}, diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml new file mode 100644 index 0000000..68719e0 --- /dev/null +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml index 21d3909..6be2414 100644 --- a/src/Ursa.Themes.Semi/Controls/_index.axaml +++ b/src/Ursa.Themes.Semi/Controls/_index.axaml @@ -4,6 +4,7 @@ + diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index d2ab31c..384c364 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -4,6 +4,7 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Metadata; +using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; @@ -47,6 +48,15 @@ public class Breadcrumb: ItemsControl get => GetValue(SeparatorProperty); set => SetValue(SeparatorProperty, value); } + + public static readonly StyledProperty IconTemplateProperty = AvaloniaProperty.Register( + nameof(IconTemplate)); + + public IDataTemplate? IconTemplate + { + get => GetValue(IconTemplateProperty); + set => SetValue(IconTemplateProperty, value); + } static Breadcrumb() { @@ -66,20 +76,23 @@ public class Breadcrumb: ItemsControl protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { base.PrepareContainerForItemOverride(container, item, index); - if (container is BreadcrumbItem breadcrumbItem) + if (container is not BreadcrumbItem breadcrumbItem) return; + if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) { - if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) + SeparatorProperty.Changed.AddClassHandler((o, e) => { - SeparatorProperty.Changed.AddClassHandler((o, e) => + breadcrumbItem.Separator = e.NewValue.Value switch { - breadcrumbItem.Separator = e.NewValue.Value switch - { - string s => s, - ITemplate t => t.Build(), - _ => e.NewValue.Value?.ToString() - }; - }); - } + string s => s, + ITemplate t => t.Build(), + _ => e.NewValue.Value?.ToString() + }; + }); + } + bool b = breadcrumbItem.IsSet(BreadcrumbItem.IconProperty); + if(!breadcrumbItem.IsSet(BreadcrumbItem.IconProperty) && IconBinding != null) + { + breadcrumbItem[!BreadcrumbItem.IconProperty] = IconBinding; } } } \ No newline at end of file diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index 1de6be1..abbaf50 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -1,6 +1,7 @@ using System.Windows.Input; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Templates; namespace Ursa.Controls; @@ -34,6 +35,15 @@ public class BreadcrumbItem: ContentControl set => SetValue(CommandProperty, value); } + public static readonly StyledProperty IconTemplateProperty = AvaloniaProperty.Register( + nameof(IconTemplate)); + + public IDataTemplate? IconTemplate + { + get => GetValue(IconTemplateProperty); + set => SetValue(IconTemplateProperty, value); + } + static BreadcrumbItem() { From 39bc26c28e0b792416ae10efef420412323c1b23 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Sun, 3 Mar 2024 00:09:30 +0800 Subject: [PATCH 3/9] feat: make sure separator is from correct level. --- demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 6 ++- .../Controls/Breadcrumb.axaml | 1 + src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 42 +++++++++++++++---- .../Controls/Breadcrumb/BreadcrumbItem.cs | 2 +- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml index ac75e8b..21ef4b6 100644 --- a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -7,9 +7,11 @@ d:DesignHeight="450" x:Class="Ursa.Demo.Pages.BreadcrumbDemo"> - + - + + + diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index 68719e0..952f592 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -17,6 +17,7 @@ + diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index 384c364..1c308a2 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -57,6 +57,15 @@ public class Breadcrumb: ItemsControl get => GetValue(IconTemplateProperty); set => SetValue(IconTemplateProperty, value); } + + public static readonly StyledProperty MaxItemCountProperty = AvaloniaProperty.Register( + nameof(MaxItemCount), defaultValue: 4); + + public int MaxItemCount + { + get => GetValue(MaxItemCountProperty); + set => SetValue(MaxItemCountProperty, value); + } static Breadcrumb() { @@ -79,20 +88,35 @@ public class Breadcrumb: ItemsControl if (container is not BreadcrumbItem breadcrumbItem) return; if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) { - SeparatorProperty.Changed.AddClassHandler((o, e) => + if (GetSeparatorInstance(Separator) is { } a) { - breadcrumbItem.Separator = e.NewValue.Value switch - { - string s => s, - ITemplate t => t.Build(), - _ => e.NewValue.Value?.ToString() - }; + breadcrumbItem.Separator = a; + } + SeparatorProperty.Changed.AddClassHandler((_, args) => + { + if (GetSeparatorInstance(args.NewValue.Value) is { } b) + breadcrumbItem.Separator = b; }); } - bool b = breadcrumbItem.IsSet(BreadcrumbItem.IconProperty); - if(!breadcrumbItem.IsSet(BreadcrumbItem.IconProperty) && IconBinding != null) + if (!breadcrumbItem.IsSet(BreadcrumbItem.IconProperty) && IconBinding != null) { breadcrumbItem[!BreadcrumbItem.IconProperty] = IconBinding; } + if (!breadcrumbItem.IsSet(BreadcrumbItem.CommandProperty) && CommandBinding != null) + { + breadcrumbItem[!BreadcrumbItem.CommandProperty] = CommandBinding; + } + if (!breadcrumbItem.IsSet(BreadcrumbItem.IconTemplateProperty) && IconTemplate != null) + { + breadcrumbItem.IconTemplate = IconTemplate; + } } + + private static object? GetSeparatorInstance(object? separator) => separator switch + { + null => null, + string s => s, + ITemplate t => t.Build(), + _ => separator.ToString() + }; } \ No newline at end of file diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index abbaf50..c6c38f9 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -9,7 +9,7 @@ public class BreadcrumbItem: ContentControl { public static readonly StyledProperty SeparatorProperty = AvaloniaProperty.Register( - nameof(Separator), "/"); + nameof(Separator)); public object? Separator { From dfff263786e06f9cd0d5d075ed15a1f765cf300f Mon Sep 17 00:00:00 2001 From: rabbitism Date: Sun, 3 Mar 2024 15:00:38 +0800 Subject: [PATCH 4/9] feat: fix content preparation logic. --- demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 46 +++++++++++++------ .../ViewModels/BreadcrumbDemoViewModel.cs | 20 +++++++- .../Controls/Breadcrumb.axaml | 16 +++++-- src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 12 ++++- 4 files changed, 75 insertions(+), 19 deletions(-) diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml index 21ef4b6..9ceef32 100644 --- a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -1,17 +1,37 @@ - + + + + - - - - - + + + + + + + + + + + + + diff --git a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs index 92f716a..591b585 100644 --- a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs @@ -1,8 +1,26 @@ +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; namespace Ursa.Demo.ViewModels; public class BreadcrumbDemoViewModel: ObservableObject { - + public ObservableCollection Items1 { get; set; } + + public BreadcrumbDemoViewModel() + { + Items1 = new ObservableCollection() + { + new BreadcrumbDemoItem() { Section = "Home", Icon = "Home" }, + new BreadcrumbDemoItem() { Section = "Page 1", Icon = "Page" }, + new BreadcrumbDemoItem() { Section = "Page 2", Icon = "Page" }, + new BreadcrumbDemoItem() { Section = "Page 3", Icon = "Page" }, + }; + } +} + +public class BreadcrumbDemoItem: ObservableObject +{ + public string Section { get; set; } + public string Icon { get; set; } } \ No newline at end of file diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index 952f592..30750b8 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -1,8 +1,18 @@ - + + + + + + + + + + + @@ -15,8 +25,8 @@ - - + + diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index 1c308a2..252ebca 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -4,7 +4,6 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Metadata; -using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; @@ -84,7 +83,8 @@ public class Breadcrumb: ItemsControl protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { - base.PrepareContainerForItemOverride(container, item, index); + // base.PrepareContainerForItemOverride(container, item, index); + if (container == item) return; if (container is not BreadcrumbItem breadcrumbItem) return; if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) { @@ -98,6 +98,14 @@ public class Breadcrumb: ItemsControl breadcrumbItem.Separator = b; }); } + if(!breadcrumbItem.IsSet(ContentControl.ContentProperty)) + { + breadcrumbItem.SetCurrentValue(ContentControl.ContentProperty, item); + if (DisplayMemberBinding is not null) + { + breadcrumbItem[!ContentControl.ContentProperty] = DisplayMemberBinding; + } + } if (!breadcrumbItem.IsSet(BreadcrumbItem.IconProperty) && IconBinding != null) { breadcrumbItem[!BreadcrumbItem.IconProperty] = IconBinding; From 4e5d9af7b5e00798747e74c4619e9991de89a8d4 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Sun, 3 Mar 2024 16:02:38 +0800 Subject: [PATCH 5/9] feat: implement semi style. --- .../ViewModels/BreadcrumbDemoViewModel.cs | 1 + .../Controls/Breadcrumb.axaml | 77 +++++++++++++++---- src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 18 ++--- .../Controls/Breadcrumb/BreadcrumbItem.cs | 3 + 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs index 591b585..1fd7535 100644 --- a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs @@ -15,6 +15,7 @@ public class BreadcrumbDemoViewModel: ObservableObject new BreadcrumbDemoItem() { Section = "Page 1", Icon = "Page" }, new BreadcrumbDemoItem() { Section = "Page 2", Icon = "Page" }, new BreadcrumbDemoItem() { Section = "Page 3", Icon = "Page" }, + new BreadcrumbDemoItem() { Section = "Page 4", Icon = "Page" }, }; } } diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index 30750b8..7d9b206 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -1,36 +1,85 @@ - + - - - - - + + + + + - + - + + - + - - - + + + + + + + + + + + + + + + + + diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index 252ebca..4818d40 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -56,15 +56,6 @@ public class Breadcrumb: ItemsControl get => GetValue(IconTemplateProperty); set => SetValue(IconTemplateProperty, value); } - - public static readonly StyledProperty MaxItemCountProperty = AvaloniaProperty.Register( - nameof(MaxItemCount), defaultValue: 4); - - public int MaxItemCount - { - get => GetValue(MaxItemCountProperty); - set => SetValue(MaxItemCountProperty, value); - } static Breadcrumb() { @@ -84,7 +75,6 @@ public class Breadcrumb: ItemsControl protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { // base.PrepareContainerForItemOverride(container, item, index); - if (container == item) return; if (container is not BreadcrumbItem breadcrumbItem) return; if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) { @@ -98,6 +88,10 @@ public class Breadcrumb: ItemsControl breadcrumbItem.Separator = b; }); } + + PseudolassesExtensions.Set(container.Classes, BreadcrumbItem.PC_Last, index == ItemCount - 1); + + if (container == item) return; if(!breadcrumbItem.IsSet(ContentControl.ContentProperty)) { breadcrumbItem.SetCurrentValue(ContentControl.ContentProperty, item); @@ -106,6 +100,10 @@ public class Breadcrumb: ItemsControl breadcrumbItem[!ContentControl.ContentProperty] = DisplayMemberBinding; } } + if (!breadcrumbItem.IsSet(ContentControl.ContentTemplateProperty) && this.ItemTemplate != null) + { + breadcrumbItem.SetCurrentValue(ContentControl.ContentTemplateProperty, this.ItemTemplate); + } if (!breadcrumbItem.IsSet(BreadcrumbItem.IconProperty) && IconBinding != null) { breadcrumbItem[!BreadcrumbItem.IconProperty] = IconBinding; diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index c6c38f9..81662ef 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -1,12 +1,15 @@ using System.Windows.Input; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Metadata; using Avalonia.Controls.Templates; namespace Ursa.Controls; +[PseudoClasses(PC_Last)] public class BreadcrumbItem: ContentControl { + public const string PC_Last = ":last"; public static readonly StyledProperty SeparatorProperty = AvaloniaProperty.Register( nameof(Separator)); From 279006633331429eacbae8523b8d23a542b84fa8 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Sun, 3 Mar 2024 16:09:17 +0800 Subject: [PATCH 6/9] feat: implement command, fix icon foreground in light mode. --- demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 1 + .../Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs | 13 +++++++++++++ src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml | 2 +- src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs | 6 ++++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml index 9ceef32..0e44740 100644 --- a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -26,6 +26,7 @@ diff --git a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs index 1fd7535..babdf6d 100644 --- a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs @@ -1,5 +1,8 @@ using System.Collections.ObjectModel; +using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Ursa.Controls; namespace Ursa.Demo.ViewModels; @@ -24,4 +27,14 @@ public class BreadcrumbDemoItem: ObservableObject { public string Section { get; set; } public string Icon { get; set; } + + public ICommand Command { get; set; } + + public BreadcrumbDemoItem() + { + Command = new RelayCommand(() => + { + MessageBox.ShowOverlayAsync(Section); + }); + } } \ No newline at end of file diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index 7d9b206..554f5d5 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -33,7 +33,7 @@ VerticalAlignment="Center" Content="{TemplateBinding Icon}" ContentTemplate="{TemplateBinding IconTemplate}" - Foreground="{TemplateBinding Foreground}" + Foreground="{DynamicResource SemiColorText2}" IsVisible="{TemplateBinding Icon, Converter={x:Static ObjectConverters.IsNotNull}}" /> SetValue(IconTemplateProperty, value); } - static BreadcrumbItem() + protected override void OnPointerPressed(PointerPressedEventArgs e) { - + base.OnPointerPressed(e); + Command?.Execute(null); } } \ No newline at end of file From fdc6b2e156682588a1ad7a4886f0b863b390df96 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 16:47:33 +0800 Subject: [PATCH 7/9] feat: introduce Small class and IsReadOnly property. --- demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 12 +++ .../Controls/Breadcrumb.axaml | 91 +++++++++++++++---- src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml | 20 ++++ src/Ursa.Themes.Semi/Styles/_index.axaml | 1 + src/Ursa/Controls/BackTop/BackTop.cs | 15 +++ src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 9 ++ .../Controls/Breadcrumb/BreadcrumbItem.cs | 7 +- 7 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml create mode 100644 src/Ursa/Controls/BackTop/BackTop.cs diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml index 0e44740..0df146e 100644 --- a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -23,6 +23,18 @@ + + + + + + + + + + + + + - + - + ContentTemplate="{TemplateBinding ContentTemplate}" + Foreground="{DynamicResource SemiColorText2}" + IsVisible="{TemplateBinding Content, + Converter={x:Static ObjectConverters.IsNotNull}}" /> + - + @@ -55,30 +63,81 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml new file mode 100644 index 0000000..997942a --- /dev/null +++ b/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/src/Ursa.Themes.Semi/Styles/_index.axaml b/src/Ursa.Themes.Semi/Styles/_index.axaml index e3cc666..baa0d9b 100644 --- a/src/Ursa.Themes.Semi/Styles/_index.axaml +++ b/src/Ursa.Themes.Semi/Styles/_index.axaml @@ -4,6 +4,7 @@ + diff --git a/src/Ursa/Controls/BackTop/BackTop.cs b/src/Ursa/Controls/BackTop/BackTop.cs new file mode 100644 index 0000000..3506807 --- /dev/null +++ b/src/Ursa/Controls/BackTop/BackTop.cs @@ -0,0 +1,15 @@ +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/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index 4818d40..b54a5ec 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -56,6 +56,15 @@ public class Breadcrumb: ItemsControl get => GetValue(IconTemplateProperty); set => SetValue(IconTemplateProperty, value); } + + public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register( + nameof(IsReadOnly)); + + public bool IsReadOnly + { + get => GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); + } static Breadcrumb() { diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index 44fad5f..35aa6e1 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -4,6 +4,7 @@ using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Templates; using Avalonia.Input; +using Avalonia.LogicalTree; namespace Ursa.Controls; @@ -51,6 +52,10 @@ public class BreadcrumbItem: ContentControl protected override void OnPointerPressed(PointerPressedEventArgs e) { base.OnPointerPressed(e); - Command?.Execute(null); + var parent = this.FindLogicalAncestorOfType(); + if (parent?.IsReadOnly != true) + { + Command?.Execute(null); + } } } \ No newline at end of file From 8ac608505b598a285866e6610bac6771f5a4a264 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 17:53:16 +0800 Subject: [PATCH 8/9] feat: move readonly to item. --- demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml | 8 ++- .../ViewModels/BreadcrumbDemoViewModel.cs | 5 +- .../Controls/Breadcrumb.axaml | 62 ++----------------- src/Ursa/Controls/Breadcrumb/Breadcrumb.cs | 9 --- .../Controls/Breadcrumb/BreadcrumbItem.cs | 12 +++- 5 files changed, 25 insertions(+), 71 deletions(-) diff --git a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml index 0df146e..101542e 100644 --- a/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml +++ b/demo/Ursa.Demo/Pages/BreadcrumbDemo.axaml @@ -19,6 +19,7 @@ + @@ -29,7 +30,7 @@ - + @@ -40,6 +41,11 @@ IconBinding="{Binding Icon}" CommandBinding="{Binding Command}" ItemsSource="{Binding Items1}"> + + + diff --git a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs index babdf6d..d5dbbee 100644 --- a/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/BreadcrumbDemoViewModel.cs @@ -18,15 +18,16 @@ public class BreadcrumbDemoViewModel: ObservableObject new BreadcrumbDemoItem() { Section = "Page 1", Icon = "Page" }, new BreadcrumbDemoItem() { Section = "Page 2", Icon = "Page" }, new BreadcrumbDemoItem() { Section = "Page 3", Icon = "Page" }, - new BreadcrumbDemoItem() { Section = "Page 4", Icon = "Page" }, + new BreadcrumbDemoItem() { Section = "Page 4", Icon = "Page", IsReadOnly = true}, }; } } -public class BreadcrumbDemoItem: ObservableObject +public partial class BreadcrumbDemoItem: ObservableObject { public string Section { get; set; } public string Icon { get; set; } + [ObservableProperty] private bool _isReadOnly; public ICommand Command { get; set; } diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index 03b74a1..a14d0e2 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -19,13 +19,9 @@ - - @@ -61,6 +57,9 @@ + - @@ -81,7 +80,7 @@ - @@ -90,55 +89,4 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index b54a5ec..4818d40 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -56,15 +56,6 @@ public class Breadcrumb: ItemsControl get => GetValue(IconTemplateProperty); set => SetValue(IconTemplateProperty, value); } - - public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register( - nameof(IsReadOnly)); - - public bool IsReadOnly - { - get => GetValue(IsReadOnlyProperty); - set => SetValue(IsReadOnlyProperty, value); - } static Breadcrumb() { diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index 35aa6e1..64aaf9f 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -49,11 +49,19 @@ public class BreadcrumbItem: ContentControl set => SetValue(IconTemplateProperty, value); } + public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register( + nameof(IsReadOnly)); + + public bool IsReadOnly + { + get => GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); + } + protected override void OnPointerPressed(PointerPressedEventArgs e) { base.OnPointerPressed(e); - var parent = this.FindLogicalAncestorOfType(); - if (parent?.IsReadOnly != true) + if (!IsReadOnly) { Command?.Execute(null); } From c238950bb05990eae94537c12c17f586729384dd Mon Sep 17 00:00:00 2001 From: rabbitism Date: Tue, 5 Mar 2024 17:58:19 +0800 Subject: [PATCH 9/9] feat: fix style for small size. --- src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml | 8 ++++++-- src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml | 12 ++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml index a14d0e2..4df2747 100644 --- a/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Controls/Breadcrumb.axaml @@ -28,7 +28,6 @@ @@ -57,6 +55,12 @@ + + diff --git a/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml b/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml index 997942a..66e6706 100644 --- a/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml +++ b/src/Ursa.Themes.Semi/Styles/Breadcrumb.axaml @@ -10,11 +10,11 @@ - - +