From 0c4b6edfc22bc98b77bba489e4b9ec3a927fe70b Mon Sep 17 00:00:00 2001 From: rabbitism Date: Wed, 27 Dec 2023 00:58:50 +0800 Subject: [PATCH] feat: start to refactor. --- demo/Ursa.Demo/Pages/IntroductionDemo.axaml | 2 + demo/Ursa.Demo/Pages/TimelineDemo.axaml | 50 ++------- .../ViewModels/TimelineDemoViewModel.cs | 24 +---- src/Ursa.Themes.Semi/Controls/Timeline.axaml | 14 +-- src/Ursa/Controls/Timeline/Timeline.cs | 92 ++++++++++++---- src/Ursa/Controls/Timeline/TimelineItem.cs | 100 ++++-------------- 6 files changed, 111 insertions(+), 171 deletions(-) diff --git a/demo/Ursa.Demo/Pages/IntroductionDemo.axaml b/demo/Ursa.Demo/Pages/IntroductionDemo.axaml index 560ab49..4fbf945 100644 --- a/demo/Ursa.Demo/Pages/IntroductionDemo.axaml +++ b/demo/Ursa.Demo/Pages/IntroductionDemo.axaml @@ -144,6 +144,7 @@ IPAddress="{Binding Address}" /> + diff --git a/demo/Ursa.Demo/Pages/TimelineDemo.axaml b/demo/Ursa.Demo/Pages/TimelineDemo.axaml index b217fad..ad01c4f 100644 --- a/demo/Ursa.Demo/Pages/TimelineDemo.axaml +++ b/demo/Ursa.Demo/Pages/TimelineDemo.axaml @@ -8,51 +8,19 @@ xmlns:viewModels="clr-namespace:Ursa.Demo.ViewModels" d:DesignHeight="450" d:DesignWidth="800" - x:CompileBindings="False" x:DataType="viewModels:TimelineDemoViewModel" + x:CompileBindings="True" mc:Ignorable="d"> - - - - - - - - + - - - - - - - - - - - - + + + + diff --git a/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs index fc9e819..ece4543 100644 --- a/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs @@ -13,7 +13,7 @@ public class TimelineDemoViewModel: ViewModelBase Time = DateTime.Now, TimeFormat = "yyyy-MM-dd HH:mm:ss", Description = "Item 1", - Content = "First", + Header = "审核中", ItemType = TimelineItemType.Success, }, new() @@ -21,7 +21,7 @@ public class TimelineDemoViewModel: ViewModelBase Time = DateTime.Now, TimeFormat = "HH:mm:ss", Description = "Item 2", - Content = "Content 2", + Header = "发布成功", ItemType = TimelineItemType.Success, }, new() @@ -29,23 +29,9 @@ public class TimelineDemoViewModel: ViewModelBase Time = DateTime.Now, TimeFormat = "HH:mm:ss", Description = "Item 3", - Content = "Content 3", + Header = "审核失败", ItemType = TimelineItemType.Ongoing, - }, - new() - { - Time = DateTime.Now, - TimeFormat = "HH:mm:ss", - Description = "Item 4", - Content = "Content 4" - }, - new() - { - Time = DateTime.Now, - TimeFormat = "HH:mm:ss", - Description = "Item 5", - Content = "Content 5" - }, + } }; } @@ -54,6 +40,6 @@ public class TimelineItemViewModel: ObservableObject public DateTime Time { get; set; } public string? TimeFormat { get; set; } public string? Description { get; set; } - public string? Content { get; set; } + public string? Header { get; set; } public TimelineItemType ItemType { get; set; } } \ No newline at end of file diff --git a/src/Ursa.Themes.Semi/Controls/Timeline.axaml b/src/Ursa.Themes.Semi/Controls/Timeline.axaml index b8f62fa..759be18 100644 --- a/src/Ursa.Themes.Semi/Controls/Timeline.axaml +++ b/src/Ursa.Themes.Semi/Controls/Timeline.axaml @@ -6,9 +6,9 @@ - - - + + + @@ -81,13 +81,9 @@ Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" + Content="{TemplateBinding Header}" + ContentTemplate="{TemplateBinding HeaderTemplate}" Foreground="Gray"> - - - - - - IconMemberBindingProperty = AvaloniaProperty.Register( + nameof(IconMemberBinding)); + + [AssignBinding] + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IBinding? IconMemberBinding + { + get => GetValue(IconMemberBindingProperty); + set => SetValue(IconMemberBindingProperty, value); + } + + public static readonly StyledProperty HeaderMemberBindingProperty = AvaloniaProperty.Register( + nameof(HeaderMemberBinding)); + + [AssignBinding] + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IBinding? HeaderMemberBinding + { + get => GetValue(HeaderMemberBindingProperty); + set => SetValue(HeaderMemberBindingProperty, value); + } + + public static readonly StyledProperty DescriptionMemberBindingProperty = AvaloniaProperty.Register( + nameof(DescriptionMemberBinding)); - public static readonly StyledProperty ItemDescriptionTemplateProperty = AvaloniaProperty.Register( - nameof(ItemDescriptionTemplate)); - - public IDataTemplate? ItemDescriptionTemplate + [AssignBinding] + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IBinding? DescriptionMemberBinding { - get => GetValue(ItemDescriptionTemplateProperty); - set => SetValue(ItemDescriptionTemplateProperty, value); + get => GetValue(DescriptionMemberBindingProperty); + set => SetValue(DescriptionMemberBindingProperty, value); + } + + + public static readonly StyledProperty IconTemplateProperty = AvaloniaProperty.Register( + nameof(IconTemplate)); + + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IDataTemplate? IconTemplate + { + get => GetValue(IconTemplateProperty); + set => SetValue(IconTemplateProperty, value); } - public Timeline() + public static readonly StyledProperty DescriptionTemplateProperty = AvaloniaProperty.Register( + nameof(DescriptionTemplate)); + + [InheritDataTypeFromItems(nameof(ItemsSource))] + public IDataTemplate? DescriptionTemplate { - ItemsView.CollectionChanged+=ItemsViewOnCollectionChanged; + get => GetValue(DescriptionTemplateProperty); + set => SetValue(DescriptionTemplateProperty, value); } - private void ItemsViewOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) { - RefreshTimelineItems(); + recycleKey = null; + return item is not TimelineItem; } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) { - base.OnPropertyChanged(change); - RefreshTimelineItems(); + if (item is TimelineItem t) return t; + return new TimelineItem(); } - private void RefreshTimelineItems() + protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { - for (int i = 0; i < this.LogicalChildren.Count; i++) + base.PrepareContainerForItemOverride(container, item, index); + if (container is TimelineItem t) { - if (this.LogicalChildren[i] is TimelineItem t) + if (IconMemberBinding != null) { - t.SetIndex(i == 0, i == this.LogicalChildren.Count - 1); + t.Bind(TimelineItem.IconProperty, IconMemberBinding); } - else if (this.LogicalChildren[i] is ContentPresenter { Child: TimelineItem t2 }) + if (HeaderMemberBinding != null) { - t2.SetIndex(i == 0, i == this.LogicalChildren.Count - 1); + t.Bind(HeaderedContentControl.HeaderProperty, HeaderMemberBinding); } + if (DescriptionMemberBinding != null) + { + t.Bind(ContentControl.ContentProperty, DescriptionMemberBinding); + } + t.SetCurrentValue(TimelineItem.IconTemplateProperty, IconTemplate); + t.SetCurrentValue(HeaderedContentControl.HeaderTemplateProperty, ItemTemplate); + t.SetCurrentValue(ContentControl.ContentTemplateProperty, DescriptionTemplate); } + } - } \ No newline at end of file diff --git a/src/Ursa/Controls/Timeline/TimelineItem.cs b/src/Ursa/Controls/Timeline/TimelineItem.cs index 0958a31..9fe8af4 100644 --- a/src/Ursa/Controls/Timeline/TimelineItem.cs +++ b/src/Ursa/Controls/Timeline/TimelineItem.cs @@ -1,101 +1,41 @@ -using System.Globalization; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Media; namespace Ursa.Controls; -[PseudoClasses(PC_First, PC_Last, PC_Default, PC_Ongoing, PC_Success, PC_Warning, PC_Error, PC_None)] -public class TimelineItem: ContentControl +public class TimelineItem: HeaderedContentControl { - private const string PC_First = ":first"; - private const string PC_Last = ":last"; - private const string PC_Default = ":default"; - private const string PC_Ongoing = ":ongoing"; - private const string PC_Success = ":success"; - private const string PC_Warning = ":warning"; - private const string PC_Error = ":error"; - private const string PC_None = ":none"; + public static readonly StyledProperty IconProperty = AvaloniaProperty.Register( + nameof(Icon)); - private static readonly IReadOnlyDictionary _itemTypeMapping = new Dictionary + public object? Icon { - {TimelineItemType.Default, PC_Default}, - {TimelineItemType.Ongoing, PC_Ongoing}, - {TimelineItemType.Success, PC_Success}, - {TimelineItemType.Warning, PC_Warning}, - {TimelineItemType.Error, PC_Error}, - }; - - public static readonly StyledProperty IconForegroundProperty = - AvaloniaProperty.Register(nameof(IconForeground)); - - public IBrush IconForeground - { - get => GetValue(IconForegroundProperty); - set => SetValue(IconForegroundProperty, value); + get => GetValue(IconProperty); + set => SetValue(IconProperty, value); } - public static readonly StyledProperty TimeProperty = AvaloniaProperty.Register( - nameof(Time)); - public DateTime Time + public static readonly StyledProperty IconTemplateProperty = AvaloniaProperty.Register( + nameof(IconTemplate)); + + public IDataTemplate? IconTemplate { - get => GetValue(TimeProperty); - set => SetValue(TimeProperty, value); + get => GetValue(IconTemplateProperty); + set => SetValue(IconTemplateProperty, value); } - public static readonly StyledProperty TimeFormatProperty = AvaloniaProperty.Register( - nameof(TimeFormat), defaultValue:CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern); + public static readonly StyledProperty TypeProperty = AvaloniaProperty.Register( + nameof(Type)); - public string? TimeFormat + public TimelineItemType Type { - get => GetValue(TimeFormatProperty); - set => SetValue(TimeFormatProperty, value); - } - - public static readonly StyledProperty DescriptionTemplateProperty = AvaloniaProperty.Register( - nameof(DescriptionTemplate)); - - public IDataTemplate DescriptionTemplate - { - get => GetValue(DescriptionTemplateProperty); - set => SetValue(DescriptionTemplateProperty, value); - } - - public static readonly StyledProperty ItemTypeProperty = AvaloniaProperty.Register( - nameof(ItemType)); - - public TimelineItemType ItemType - { - get => GetValue(ItemTypeProperty); - set => SetValue(ItemTypeProperty, value); - } - - internal void SetIndex(bool isFirst, bool isLast) - { - PseudoClasses.Set(PC_First, isFirst); - PseudoClasses.Set(PC_Last, isLast); - } - - static TimelineItem() - { - ItemTypeProperty.Changed.AddClassHandler((o, e) => { o.OnItemTypeChanged(e); }); - IconForegroundProperty.Changed.AddClassHandler((o, e) => { o.OnIconForegroundChanged(e); }); - } - - private void OnItemTypeChanged(AvaloniaPropertyChangedEventArgs args) - { - var oldValue = args.GetOldValue(); - var newValue = args.GetNewValue(); - PseudoClasses.Set(_itemTypeMapping[oldValue], false); - PseudoClasses.Set(_itemTypeMapping[newValue], true); - } - - private void OnIconForegroundChanged(AvaloniaPropertyChangedEventArgs args) - { - IBrush? newValue = args.GetOldValue(); - PseudoClasses.Set(PC_None, newValue is null); + get => GetValue(TypeProperty); + set => SetValue(TypeProperty, value); } + + } \ No newline at end of file