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