From 0f139264ccd105bcf8e8f4b0f385cc6e560b8146 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Thu, 23 Mar 2023 12:52:02 +0800 Subject: [PATCH] feat: add demo page, prepare collection changed behavior. --- demo/Ursa.Demo/Pages/TimelineDemo.axaml | 25 ++++ demo/Ursa.Demo/Pages/TimelineDemo.axaml.cs | 15 +++ .../ViewModels/TimelineDemoViewModel.cs | 110 ++++++++++++++++++ demo/Ursa.Demo/Views/MainWindow.axaml | 3 + src/Ursa.Themes.Semi/Controls/Timeline.axaml | 51 ++++++++ src/Ursa.Themes.Semi/Controls/_index.axaml | 1 + src/Ursa/Controls/Timeline/Timeline.cs | 39 ++++--- .../Timeline/TimelineFormatConverter.cs | 17 +++ src/Ursa/Controls/Timeline/TimelineItem.cs | 11 +- .../Controls/Timeline/TimelineItemData.cs | 9 -- .../Controls/Timeline/TimelinePlacement.cs | 12 -- 11 files changed, 253 insertions(+), 40 deletions(-) create mode 100644 demo/Ursa.Demo/Pages/TimelineDemo.axaml create mode 100644 demo/Ursa.Demo/Pages/TimelineDemo.axaml.cs create mode 100644 demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs create mode 100644 src/Ursa.Themes.Semi/Controls/Timeline.axaml create mode 100644 src/Ursa/Controls/Timeline/TimelineFormatConverter.cs delete mode 100644 src/Ursa/Controls/Timeline/TimelineItemData.cs delete mode 100644 src/Ursa/Controls/Timeline/TimelinePlacement.cs diff --git a/demo/Ursa.Demo/Pages/TimelineDemo.axaml b/demo/Ursa.Demo/Pages/TimelineDemo.axaml new file mode 100644 index 0000000..674a2c4 --- /dev/null +++ b/demo/Ursa.Demo/Pages/TimelineDemo.axaml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/demo/Ursa.Demo/Pages/TimelineDemo.axaml.cs b/demo/Ursa.Demo/Pages/TimelineDemo.axaml.cs new file mode 100644 index 0000000..fe07b76 --- /dev/null +++ b/demo/Ursa.Demo/Pages/TimelineDemo.axaml.cs @@ -0,0 +1,15 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Ursa.Demo.ViewModels; + +namespace Ursa.Demo.Pages; + +public partial class TimelineDemo : UserControl +{ + public TimelineDemo() + { + InitializeComponent(); + this.DataContext = new TimelineDemoViewModel(); + } +} \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs new file mode 100644 index 0000000..29f72f7 --- /dev/null +++ b/demo/Ursa.Demo/ViewModels/TimelineDemoViewModel.cs @@ -0,0 +1,110 @@ +using System; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Ursa.Demo.ViewModels; + +public class TimelineDemoViewModel: ObservableObject +{ + public TimelineItemViewModel[] Items { get; } = + { + new() + { + Time = DateTime.Now, + TimeFormat = "yyyy-MM-dd HH:mm:ss", + Description = "Item 1", + Content = "First" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 2", + Content = "Content 2" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 3", + Content = "Content 3" + }, + 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" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 6", + Content = "Content 6" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 7", + Content = "Content 7" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 8", + Content = "Content 8" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 9", + Content = "Content 9" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 10", + Content = "Content 10" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 11", + Content = "Content 11" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 12", + Content = "Content 12" + }, + new() + { + Time = DateTime.Now, + TimeFormat = "HH:mm:ss", + Description = "Item 13", + Content = "Last" + } + }; +} + +public class TimelineItemViewModel: ObservableObject +{ + public DateTime Time { get; set; } + public string? TimeFormat { get; set; } + public string? Description { get; set; } + public string? Content { get; set; } +} \ No newline at end of file diff --git a/demo/Ursa.Demo/Views/MainWindow.axaml b/demo/Ursa.Demo/Views/MainWindow.axaml index de1f2dd..9ba93b8 100644 --- a/demo/Ursa.Demo/Views/MainWindow.axaml +++ b/demo/Ursa.Demo/Views/MainWindow.axaml @@ -35,6 +35,9 @@ + + + diff --git a/src/Ursa.Themes.Semi/Controls/Timeline.axaml b/src/Ursa.Themes.Semi/Controls/Timeline.axaml new file mode 100644 index 0000000..002d236 --- /dev/null +++ b/src/Ursa.Themes.Semi/Controls/Timeline.axaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml index 4d15016..7c08f47 100644 --- a/src/Ursa.Themes.Semi/Controls/_index.axaml +++ b/src/Ursa.Themes.Semi/Controls/_index.axaml @@ -5,5 +5,6 @@ + diff --git a/src/Ursa/Controls/Timeline/Timeline.cs b/src/Ursa/Controls/Timeline/Timeline.cs index 34daef6..23e52dc 100644 --- a/src/Ursa/Controls/Timeline/Timeline.cs +++ b/src/Ursa/Controls/Timeline/Timeline.cs @@ -1,6 +1,11 @@ +using System.Collections.Specialized; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices.ComTypes; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Generators; +using Avalonia.Controls.Presenters; +using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; namespace Ursa.Controls; @@ -17,33 +22,33 @@ public class Timeline: ItemsControl set => SetValue(ItemDescriptionTemplateProperty, value); } - protected override bool IsItemItsOwnContainerOverride(Control item) + public Timeline() { - return item is TimelineItem; + ItemsView.CollectionChanged+=ItemsViewOnCollectionChanged; } - protected override Control CreateContainerForItemOverride() + private void ItemsViewOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - return new TimelineItem(); + RefreshTimelineItems(); } - - protected override void PrepareContainerForItemOverride(Control container, object? item, int index) + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { - base.PrepareContainerForItemOverride(container, item, index); - if (container is TimelineItem c ) + base.OnPropertyChanged(change); + RefreshTimelineItems(); + } + + private void RefreshTimelineItems() + { + for (int i = 0; i < this.LogicalChildren.Count; i++) { - if (item is ITimelineItemData data) + if (this.LogicalChildren[i] is TimelineItem t) { - c[TimelineItem.TimeProperty] = data; - c[ContentControl.ContentProperty] = data.Content; - c[TimelineItem.DescriptionProperty] = data.Description; - if(ItemTemplate is {}) c[ContentControl.ContentTemplateProperty] = this.ItemTemplate; - if(ItemDescriptionTemplate is {}) c[TimelineItem.DescriptionTemplateProperty] = this.ItemDescriptionTemplate; + t.SetPosition(i == 0, i == this.LogicalChildren.Count - 1); } - else + else if (this.LogicalChildren[i] is ContentPresenter { Child: TimelineItem t2 }) { - c.Content = item; - if (ItemTemplate is { }) c[ContentControl.ContentTemplateProperty] = this.ItemTemplate; + t2.SetPosition(i == 0, i == this.LogicalChildren.Count - 1); } } } diff --git a/src/Ursa/Controls/Timeline/TimelineFormatConverter.cs b/src/Ursa/Controls/Timeline/TimelineFormatConverter.cs new file mode 100644 index 0000000..48cdc8f --- /dev/null +++ b/src/Ursa/Controls/Timeline/TimelineFormatConverter.cs @@ -0,0 +1,17 @@ +using System.Globalization; +using Avalonia; +using Avalonia.Data.Converters; + +namespace Ursa.Controls; + +public class TimelineFormatConverter: IMultiValueConverter +{ + public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) + { + if (values.Count> 1 && values[0] is DateTime date && values[1] is string s) + { + return date.ToString(s, culture); + } + return AvaloniaProperty.UnsetValue; + } +} \ No newline at end of file diff --git a/src/Ursa/Controls/Timeline/TimelineItem.cs b/src/Ursa/Controls/Timeline/TimelineItem.cs index 8628063..0139823 100644 --- a/src/Ursa/Controls/Timeline/TimelineItem.cs +++ b/src/Ursa/Controls/Timeline/TimelineItem.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -12,7 +13,7 @@ public class TimelineItem: ContentControl { public const string PC_First = ":first"; public const string PC_Last = ":last"; - + public static readonly StyledProperty IconForegroundProperty = AvaloniaProperty.Register(nameof(IconForeground)); @@ -40,7 +41,7 @@ public class TimelineItem: ContentControl } public static readonly StyledProperty TimeFormatProperty = AvaloniaProperty.Register( - nameof(TimeFormat)); + nameof(TimeFormat), defaultValue:CultureInfo.CurrentUICulture.DateTimeFormat.SortableDateTimePattern); public string? TimeFormat { @@ -56,4 +57,10 @@ public class TimelineItem: ContentControl get => GetValue(DescriptionTemplateProperty); set => SetValue(DescriptionTemplateProperty, value); } + + internal void SetPosition(bool isFirst, bool isLast) + { + PseudoClasses.Set(PC_First, isFirst); + PseudoClasses.Set(PC_Last, isLast); + } } \ No newline at end of file diff --git a/src/Ursa/Controls/Timeline/TimelineItemData.cs b/src/Ursa/Controls/Timeline/TimelineItemData.cs deleted file mode 100644 index 1d4b7c0..0000000 --- a/src/Ursa/Controls/Timeline/TimelineItemData.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ursa.Controls; - -public interface ITimelineItemData -{ - public DateTime Time { get; set; } - public object Content { get; set; } - public object Description { get; set; } - public TimelineItemType ItemType { get; set; } -} \ No newline at end of file diff --git a/src/Ursa/Controls/Timeline/TimelinePlacement.cs b/src/Ursa/Controls/Timeline/TimelinePlacement.cs deleted file mode 100644 index adf11bb..0000000 --- a/src/Ursa/Controls/Timeline/TimelinePlacement.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ursa.Controls; - -/// -/// Describe how TimelineItem components should be placed around the line. -/// -public enum TimelinePlacement -{ - Left, - Right, - Center, - Alternate, -} \ No newline at end of file