feat: start to refactor.

This commit is contained in:
rabbitism
2023-12-27 00:58:50 +08:00
parent 5ac95a9965
commit 0c4b6edfc2
6 changed files with 111 additions and 171 deletions

View File

@@ -1,56 +1,104 @@
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;
using Avalonia.Data;
using Avalonia.Metadata;
namespace Ursa.Controls;
public class Timeline: ItemsControl
{
public static readonly StyledProperty<IBinding?> IconMemberBindingProperty = AvaloniaProperty.Register<Timeline, IBinding?>(
nameof(IconMemberBinding));
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IBinding? IconMemberBinding
{
get => GetValue(IconMemberBindingProperty);
set => SetValue(IconMemberBindingProperty, value);
}
public static readonly StyledProperty<IBinding?> HeaderMemberBindingProperty = AvaloniaProperty.Register<Timeline, IBinding?>(
nameof(HeaderMemberBinding));
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IBinding? HeaderMemberBinding
{
get => GetValue(HeaderMemberBindingProperty);
set => SetValue(HeaderMemberBindingProperty, value);
}
public static readonly StyledProperty<IBinding?> DescriptionMemberBindingProperty = AvaloniaProperty.Register<Timeline, IBinding?>(
nameof(DescriptionMemberBinding));
public static readonly StyledProperty<IDataTemplate?> ItemDescriptionTemplateProperty = AvaloniaProperty.Register<Timeline, IDataTemplate?>(
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<IDataTemplate?> IconTemplateProperty = AvaloniaProperty.Register<Timeline, IDataTemplate?>(
nameof(IconTemplate));
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IDataTemplate? IconTemplate
{
get => GetValue(IconTemplateProperty);
set => SetValue(IconTemplateProperty, value);
}
public Timeline()
public static readonly StyledProperty<IDataTemplate?> DescriptionTemplateProperty = AvaloniaProperty.Register<Timeline, IDataTemplate?>(
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);
}
}
}

View File

@@ -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<object?> IconProperty = AvaloniaProperty.Register<TimelineItem, object?>(
nameof(Icon));
private static readonly IReadOnlyDictionary<TimelineItemType, string> _itemTypeMapping = new Dictionary<TimelineItemType, string>
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<IBrush> IconForegroundProperty =
AvaloniaProperty.Register<TimelineItem, IBrush>(nameof(IconForeground));
public IBrush IconForeground
{
get => GetValue(IconForegroundProperty);
set => SetValue(IconForegroundProperty, value);
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public static readonly StyledProperty<DateTime> TimeProperty = AvaloniaProperty.Register<TimelineItem, DateTime>(
nameof(Time));
public DateTime Time
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty = AvaloniaProperty.Register<TimelineItem, IDataTemplate?>(
nameof(IconTemplate));
public IDataTemplate? IconTemplate
{
get => GetValue(TimeProperty);
set => SetValue(TimeProperty, value);
get => GetValue(IconTemplateProperty);
set => SetValue(IconTemplateProperty, value);
}
public static readonly StyledProperty<string?> TimeFormatProperty = AvaloniaProperty.Register<TimelineItem, string?>(
nameof(TimeFormat), defaultValue:CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern);
public static readonly StyledProperty<TimelineItemType> TypeProperty = AvaloniaProperty.Register<TimelineItem, TimelineItemType>(
nameof(Type));
public string? TimeFormat
public TimelineItemType Type
{
get => GetValue(TimeFormatProperty);
set => SetValue(TimeFormatProperty, value);
}
public static readonly StyledProperty<IDataTemplate> DescriptionTemplateProperty = AvaloniaProperty.Register<TimelineItem, IDataTemplate>(
nameof(DescriptionTemplate));
public IDataTemplate DescriptionTemplate
{
get => GetValue(DescriptionTemplateProperty);
set => SetValue(DescriptionTemplateProperty, value);
}
public static readonly StyledProperty<TimelineItemType> ItemTypeProperty = AvaloniaProperty.Register<TimelineItem, TimelineItemType>(
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<TimelineItem>((o, e) => { o.OnItemTypeChanged(e); });
IconForegroundProperty.Changed.AddClassHandler<TimelineItem>((o, e) => { o.OnIconForegroundChanged(e); });
}
private void OnItemTypeChanged(AvaloniaPropertyChangedEventArgs args)
{
var oldValue = args.GetOldValue<TimelineItemType>();
var newValue = args.GetNewValue<TimelineItemType>();
PseudoClasses.Set(_itemTypeMapping[oldValue], false);
PseudoClasses.Set(_itemTypeMapping[newValue], true);
}
private void OnIconForegroundChanged(AvaloniaPropertyChangedEventArgs args)
{
IBrush? newValue = args.GetOldValue<IBrush?>();
PseudoClasses.Set(PC_None, newValue is null);
get => GetValue(TypeProperty);
set => SetValue(TypeProperty, value);
}
}