From 855edf7d6d98c1784b4de643db61c9b5d6310007 Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Wed, 2 Oct 2024 21:47:59 +0100 Subject: [PATCH] Drop ValueViewModel, and expand ObservableCollection to support Value/ViewModel, and Key/Value/ViewModel --- Toolkit.Foundation/CommandValueViewModel.cs | 3 +- .../ConfigurationValueViewModel.cs | 75 ++++++- Toolkit.Foundation/Observable.cs | 6 +- Toolkit.Foundation/ObservableCollection.cs | 212 +++++++++--------- Toolkit.Foundation/ValueViewModel.cs | 21 -- Toolkit.UI.Avalonia/EventListenerBehaviour.cs | 2 +- .../Themes/ControlResources.axaml | 60 +++++ 7 files changed, 250 insertions(+), 129 deletions(-) delete mode 100644 Toolkit.Foundation/ValueViewModel.cs diff --git a/Toolkit.Foundation/CommandValueViewModel.cs b/Toolkit.Foundation/CommandValueViewModel.cs index dd8bbb4..fd2e5c7 100644 --- a/Toolkit.Foundation/CommandValueViewModel.cs +++ b/Toolkit.Foundation/CommandValueViewModel.cs @@ -8,7 +8,8 @@ public partial class CommandValueViewModel(IServiceProvider provider, IPublisher publisher, ISubscriber subscriber, IDisposer disposer) : - ValueViewModel(provider, factory, mediator, publisher, subscriber, disposer) + Observable(provider, factory, mediator, publisher, subscriber, disposer) + where TValue : notnull { public IRelayCommand InvokeCommand => new AsyncRelayCommand(InvokeAsync); diff --git a/Toolkit.Foundation/ConfigurationValueViewModel.cs b/Toolkit.Foundation/ConfigurationValueViewModel.cs index a208002..358d084 100644 --- a/Toolkit.Foundation/ConfigurationValueViewModel.cs +++ b/Toolkit.Foundation/ConfigurationValueViewModel.cs @@ -1,4 +1,5 @@ -namespace Toolkit.Foundation; + +namespace Toolkit.Foundation; public partial class ConfigurationValueViewModel(IServiceProvider provider, IServiceFactory factory, @@ -10,13 +11,83 @@ public partial class ConfigurationValueViewModel(IServic IWritableConfiguration writer, Func read, Action write) : - ValueViewModel(provider, factory, mediator, publisher, subscriber, disposer), + Observable(provider, factory, mediator, publisher, subscriber, disposer), INotificationHandler> where TConfiguration : class { public Task Handle(ChangedEventArgs args) { + throw new NotImplementedException(); + } + protected override void OnChanged(TValue? value) + { + writer.Write(args => write(value, args)); + base.OnChanged(value); + } + + public override Task OnActivated() + { + Value = read(configuration); + return base.OnActivated(); + } +} + +public partial class ConfigurationValueViewModel : + ObservableCollection, + INotificationHandler> + where TConfiguration : class + where TItem : notnull, + IDisposable +{ + private readonly TConfiguration configuration; + private readonly IWritableConfiguration writer; + private readonly Func read; + private readonly Action write; + + public ConfigurationValueViewModel(IServiceProvider provider, + IServiceFactory factory, + IMediator mediator, + IPublisher publisher, + ISubscriber subscriber, + IDisposer disposer, + TConfiguration configuration, + IWritableConfiguration writer, + Func read, + Action write, + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer, value) + { + this.configuration = configuration; + this.writer = writer; + this.read = read; + this.write = write; + + Value = value; + } + + public ConfigurationValueViewModel(IServiceProvider provider, + IServiceFactory factory, + IMediator mediator, + IPublisher publisher, + ISubscriber subscriber, + IDisposer disposer, + IEnumerable items, + TConfiguration configuration, + IWritableConfiguration writer, + Func read, + Action write, + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer, items, value) + { + this.configuration = configuration; + this.writer = writer; + this.read = read; + this.write = write; + + Value = value; + } + + public Task Handle(ChangedEventArgs args) + { throw new NotImplementedException(); } diff --git a/Toolkit.Foundation/Observable.cs b/Toolkit.Foundation/Observable.cs index 8ef169e..cfd0abe 100644 --- a/Toolkit.Foundation/Observable.cs +++ b/Toolkit.Foundation/Observable.cs @@ -110,7 +110,6 @@ public partial class Observable(IServiceProvider provider, public partial class Observable : Observable - where TValue : notnull { [ObservableProperty] private TValue? value; @@ -126,16 +125,15 @@ public partial class Observable : Value = value; } - protected virtual void OnValueChanged() + protected virtual void OnChanged(TValue? value) { } - partial void OnValueChanged(TValue? value) => OnValueChanged(); + partial void OnValueChanged(TValue? value) => OnChanged(value); } public partial class Observable : Observable - where TKey : notnull { [ObservableProperty] private TKey key; diff --git a/Toolkit.Foundation/ObservableCollection.cs b/Toolkit.Foundation/ObservableCollection.cs index 7d229de..2021c70 100644 --- a/Toolkit.Foundation/ObservableCollection.cs +++ b/Toolkit.Foundation/ObservableCollection.cs @@ -7,35 +7,35 @@ using System.Reactive.Disposables; namespace Toolkit.Foundation; -public partial class ObservableCollection : +public partial class ObservableCollection : ObservableObject, - IObservableCollectionViewModel, + IObservableCollectionViewModel, IInitialization, IActivated, IDeactivating, IDeactivated, - IList, + IList, IList, - IReadOnlyList, + IReadOnlyList, INotifyCollectionChanged, - ICollectionSynchronization, + ICollectionSynchronization, IServiceProviderRequired, IServiceFactoryRequired, IMediatorRequired, IPublisherRequired, IDisposerRequired, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, - INotificationHandler> - where TItem : notnull, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler> + where TViewModel : notnull, IDisposable { - private readonly System.Collections.ObjectModel.ObservableCollection collection = []; + private readonly System.Collections.ObjectModel.ObservableCollection collection = []; private readonly IDispatcher dispatcher; @@ -55,7 +55,7 @@ public partial class ObservableCollection : private bool isInitialized; [ObservableProperty] - private TItem? selectedItem; + private TViewModel? selectedItem; public ObservableCollection(IServiceProvider provider, IServiceFactory factory, @@ -81,7 +81,7 @@ public partial class ObservableCollection : IPublisher publisher, ISubscriber subscriber, IDisposer disposer, - IEnumerable items) + IEnumerable items) { Provider = provider; Factory = factory; @@ -104,7 +104,7 @@ public partial class ObservableCollection : bool IList.IsFixedSize => false; - bool ICollection.IsReadOnly => false; + bool ICollection.IsReadOnly => false; bool IList.IsReadOnly => false; @@ -120,7 +120,7 @@ public partial class ObservableCollection : object ICollection.SyncRoot => this; - public TItem this[int index] + public TViewModel this[int index] { get => collection[index]; set => SetItem(index, value); @@ -131,11 +131,11 @@ public partial class ObservableCollection : get => index >= 0 && collection.Count > 0 ? collection[index] : null; set { - TItem? item = default; + TViewModel? item = default; try { - item = (TItem)value!; + item = (TViewModel)value!; } catch (InvalidCastException) { @@ -145,12 +145,12 @@ public partial class ObservableCollection : } } - private Func? defaultSelectionFactory; + private Func? defaultSelectionFactory; - public void SetSource(IList source, - Func? defaultSelectionFactory) + public void SetSource(IList source, + Func? defaultSelectionFactory) { - foreach (TItem item in source) + foreach (TViewModel item in source) { Add(item); } @@ -176,7 +176,7 @@ public partial class ObservableCollection : case NotifyCollectionChangedAction.Add: if (args.NewItems is not null) { - foreach (TItem newItem in args.NewItems) + foreach (TViewModel newItem in args.NewItems) { Add(newItem); } @@ -186,9 +186,9 @@ public partial class ObservableCollection : case NotifyCollectionChangedAction.Remove: if (args.OldItems is not null) { - foreach (TItem oldItem in args.OldItems) + foreach (TViewModel oldItem in args.OldItems) { - if (this.FirstOrDefault(x => x.Equals(oldItem)) is TItem removedItem) + if (this.FirstOrDefault(x => x.Equals(oldItem)) is TViewModel removedItem) { Remove(removedItem); } @@ -199,9 +199,9 @@ public partial class ObservableCollection : case NotifyCollectionChangedAction.Reset: Clear(); - if (sender is IEnumerable collection) + if (sender is IEnumerable collection) { - foreach (TItem item in collection) + foreach (TViewModel item in collection) { Add(item); } @@ -227,8 +227,8 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public TItem Add(params object?[] parameters) - where T : TItem + public TViewModel Add(params object?[] parameters) + where T : TViewModel { T? item = Factory.Create(args => { @@ -242,7 +242,7 @@ public partial class ObservableCollection : return item; } - public void Add(TItem item) + public void Add(TViewModel item) { int index = collection.Count; InsertItem(index, item); @@ -253,16 +253,16 @@ public partial class ObservableCollection : public void Add(object item) { int index = collection.Count; - InsertItem(index, (TItem)item); + InsertItem(index, (TViewModel)item); } int IList.Add(object? value) { - TItem? item = default; + TViewModel? item = default; try { - item = (TItem)value!; + item = (TViewModel)value!; } catch (InvalidCastException) { @@ -272,9 +272,9 @@ public partial class ObservableCollection : return Count - 1; } - public void AddRange(IEnumerable items) + public void AddRange(IEnumerable items) { - foreach (TItem? item in items) + foreach (TViewModel? item in items) { if (item is IInitialization initialization) { @@ -285,7 +285,7 @@ public partial class ObservableCollection : } } - public void Reset(Action> factory, bool disposeItems = true) + public void Reset(Action> factory, bool disposeItems = true) { SelectedItem = default; @@ -298,7 +298,7 @@ public partial class ObservableCollection : isClearing = true; if (disposeItems) { - foreach (TItem item in this.ToList()) + foreach (TViewModel item in this.ToList()) { Disposer.Dispose(item); Disposer.Remove(this, item); @@ -312,7 +312,7 @@ public partial class ObservableCollection : public void Clear() { isClearing = true; - foreach (TItem item in this.ToList()) + foreach (TViewModel item in this.ToList()) { Disposer.Dispose(item); Disposer.Remove(this, item); @@ -330,17 +330,17 @@ public partial class ObservableCollection : } } - public bool Contains(TItem item) => + public bool Contains(TViewModel item) => collection.Contains(item); bool IList.Contains(object? value) => - IsCompatibleObject(value) && Contains((TItem)value!); + IsCompatibleObject(value) && Contains((TViewModel)value!); - public void CopyTo(TItem[] array, int index) => + public void CopyTo(TViewModel[] array, int index) => collection.CopyTo(array, index); void ICollection.CopyTo(Array array, int index) => - collection.CopyTo((TItem[])array, index); + collection.CopyTo((TViewModel[])array, index); public virtual Task OnDeactivated() { @@ -369,17 +369,17 @@ public partial class ObservableCollection : Publisher.Publish(builder.Value, builder.Key); } - public IEnumerator GetEnumerator() => + public IEnumerator GetEnumerator() => collection.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)collection).GetEnumerator(); - public Task Handle(RemoveEventArgs args) + public Task Handle(RemoveEventArgs args) { if (IsActivated) { - foreach (TItem item in this.ToList()) + foreach (TViewModel item in this.ToList()) { if (args.Sender is not null && args.Sender.Equals(item)) { @@ -395,11 +395,11 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(CreateEventArgs args) + public Task Handle(CreateEventArgs args) { if (IsActivated) { - if (args.Sender is TItem item) + if (args.Sender is TViewModel item) { Add(item); } @@ -412,11 +412,11 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(InsertEventArgs args) + public Task Handle(InsertEventArgs args) { if (IsActivated) { - if (args.Sender is TItem item) + if (args.Sender is TViewModel item) { Insert(args.Index, item); } @@ -429,7 +429,7 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(MoveToEventArgs args) + public Task Handle(MoveToEventArgs args) { if (IsActivated) { @@ -443,11 +443,11 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(MoveEventArgs args) + public Task Handle(MoveEventArgs args) { if (IsActivated) { - if (args.Sender is TItem item) + if (args.Sender is TViewModel item) { Move(args.Index, item); } @@ -460,11 +460,11 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(ReplaceEventArgs args) + public Task Handle(ReplaceEventArgs args) { if (IsActivated) { - if (args.Sender is TItem item) + if (args.Sender is TViewModel item) { Replace(args.Index, item); } @@ -477,7 +477,7 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(RemoveAtEventArgs args) + public Task Handle(RemoveAtEventArgs args) { if (IsActivated) { @@ -495,15 +495,15 @@ public partial class ObservableCollection : return Task.CompletedTask; } - public Task Handle(SelectionEventArgs args) => + public Task Handle(SelectionEventArgs args) => Task.CompletedTask; - public int IndexOf(TItem item) => + public int IndexOf(TViewModel item) => collection.IndexOf(item); int IList.IndexOf(object? value) => IsCompatibleObject(value) ? - IndexOf((TItem)value!) : -1; + IndexOf((TViewModel)value!) : -1; public virtual void OnInitialize() { @@ -524,10 +524,10 @@ public partial class ObservableCollection : Activate(); } - public TItem Insert(int index = 0, + public TViewModel Insert(int index = 0, params object?[] parameters) where T : - TItem + TViewModel { T? item = Factory.Create(args => { @@ -544,7 +544,7 @@ public partial class ObservableCollection : } public void Insert(int index, - TItem item) + TViewModel item) { InsertItem(index, item); UpdateSelection(item); @@ -553,7 +553,7 @@ public partial class ObservableCollection : void IList.Insert(int index, object? value) { - if (value is TItem item) + if (value is TViewModel item) { Insert(index, item); UpdateSelection(item); @@ -567,7 +567,7 @@ public partial class ObservableCollection : return false; } - TItem item = this[oldIndex]; + TViewModel item = this[oldIndex]; bool moveSelection = false; if (item is ISelectable oldSelection) @@ -594,7 +594,7 @@ public partial class ObservableCollection : return true; } - public bool Move(int index, TItem item) + public bool Move(int index, TViewModel item) { int oldIndex = collection.IndexOf(item); if (oldIndex < 0) @@ -608,7 +608,7 @@ public partial class ObservableCollection : return true; } - public bool Remove(TItem item) + public bool Remove(TViewModel item) { int index = collection.IndexOf(item); if (index < 0) @@ -619,13 +619,13 @@ public partial class ObservableCollection : Disposer.Dispose(item); Disposer.Remove(this, item); - TItem? oldSelection = SelectedItem; + TViewModel? oldSelection = SelectedItem; RemoveItem(index); if (item.Equals(oldSelection)) { int newIndex = Math.Min(index, Count - 1); - TItem? selectedItem = newIndex >= 0 ? this[newIndex] : default; + TViewModel? selectedItem = newIndex >= 0 ? this[newIndex] : default; dispatcher.Invoke(() => SelectedItem = selectedItem); } @@ -636,7 +636,7 @@ public partial class ObservableCollection : { if (IsCompatibleObject(value)) { - Remove((TItem)value!); + Remove((TViewModel)value!); } } @@ -644,7 +644,7 @@ public partial class ObservableCollection : RemoveItem(index); public bool Replace(int index, - TItem item) + TViewModel item) { if (index <= Count - 1) { @@ -688,13 +688,13 @@ public partial class ObservableCollection : } protected virtual ActivationBuilder ActivationBuilder() => - new(new ActivationEventArgs()); + new(new ActivationEventArgs()); protected virtual void ClearItems() => collection.Clear(); protected virtual void InsertItem(int index, - TItem item) + TViewModel item) { Disposer.Add(this, item); Disposer.Add(item, Disposable.Create(() => @@ -716,11 +716,11 @@ public partial class ObservableCollection : protected virtual void RemoveItem(int index) => collection.RemoveAt(index); - protected virtual void SetItem(int index, TItem item) => + protected virtual void SetItem(int index, TViewModel item) => collection[index] = item; private static bool IsCompatibleObject(object? value) => - (value is TItem) || (value == null && default(TItem) == null); + (value is TViewModel) || (value == null && default(TViewModel) == null); private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) { @@ -740,7 +740,7 @@ public partial class ObservableCollection : } } - partial void OnSelectedItemChanged(TItem? oldValue, TItem? newValue) + partial void OnSelectedItemChanged(TViewModel? oldValue, TViewModel? newValue) { if (oldValue is ISelectable oldSelection) { @@ -760,7 +760,7 @@ public partial class ObservableCollection : { } - private void UpdateSelection(TItem item) + private void UpdateSelection(TViewModel item) { if (item is ISelectable newSelection) { @@ -777,35 +777,53 @@ public partial class ObservableCollection : } } -public partial class ObservableCollection(IServiceProvider provider, - IServiceFactory factory, - IMediator mediator, - IPublisher publisher, - ISubscriber subscriber, - IDisposer disposer, - TValue value) : ObservableCollection(provider, factory, mediator, publisher, subscriber, disposer) - where TViewModel : notnull, IDisposable +public partial class ObservableCollection : + ObservableCollection + where TViewModel : IDisposable { [ObservableProperty] - private TValue value = value; + private TValue? value; - protected virtual void OnValueChanged() + public ObservableCollection(IServiceProvider provider, + IServiceFactory factory, + IMediator mediator, + IPublisher publisher, + ISubscriber subscriber, + IDisposer disposer, + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer) { + Value = value; } - partial void OnValueChanged(TValue value) => OnValueChanged(); + public ObservableCollection(IServiceProvider provider, + IServiceFactory factory, + IMediator mediator, + IPublisher publisher, + ISubscriber subscriber, + IDisposer disposer, + IEnumerable items, + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer, items) + { + Value = value; + } + + protected virtual void OnChanged(TValue? value) + { + + } + + partial void OnValueChanged(TValue? value) => OnChanged(value); } public partial class ObservableCollection : ObservableCollection - where TViewModel : notnull, IDisposable - where TKey : notnull + where TViewModel : IDisposable { [ObservableProperty] private TKey key; [ObservableProperty] - private TValue value; + private TValue? value; public ObservableCollection(IServiceProvider provider, IServiceFactory factory, @@ -814,7 +832,7 @@ public partial class ObservableCollection : ISubscriber subscriber, IDisposer disposer, TKey key, - TValue value) : base(provider, factory, mediator, publisher, subscriber, disposer) + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer) { Key = key; Value = value; @@ -828,17 +846,11 @@ public partial class ObservableCollection : IDisposer disposer, IEnumerable items, TKey key, - TValue value) : base(provider, factory, mediator, publisher, subscriber, disposer, items) + TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer, items) { Key = key; Value = value; } - - protected virtual void OnValueChanged() - { - } - - partial void OnValueChanged(TValue value) => OnValueChanged(); } public class ObservableCollection : diff --git a/Toolkit.Foundation/ValueViewModel.cs b/Toolkit.Foundation/ValueViewModel.cs deleted file mode 100644 index 3f39cfa..0000000 --- a/Toolkit.Foundation/ValueViewModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using CommunityToolkit.Mvvm.ComponentModel; - -namespace Toolkit.Foundation; - -public partial class ValueViewModel(IServiceProvider provider, - IServiceFactory factory, - IMediator mediator, - IPublisher publisher, - ISubscriber subscriber, - IDisposer disposer) : - Observable(provider, factory, mediator, publisher, subscriber, disposer) -{ - [ObservableProperty] - private TValue? value; - - protected virtual void OnChanged(TValue? value) - { - } - - partial void OnValueChanged(TValue? value) => OnChanged(value); -} \ No newline at end of file diff --git a/Toolkit.UI.Avalonia/EventListenerBehaviour.cs b/Toolkit.UI.Avalonia/EventListenerBehaviour.cs index 83ec6f7..b0004c9 100644 --- a/Toolkit.UI.Avalonia/EventListenerBehaviour.cs +++ b/Toolkit.UI.Avalonia/EventListenerBehaviour.cs @@ -14,7 +14,7 @@ public class EventListenerBehaviour : public static readonly StyledProperty SourceProperty = AvaloniaProperty.Register(nameof(Source)); - private Delegate? eventHandler; + private readonly Delegate? eventHandler; private object? resolvedSource; static EventListenerBehaviour() diff --git a/Toolkit.UI.Controls.Avalonia/Themes/ControlResources.axaml b/Toolkit.UI.Controls.Avalonia/Themes/ControlResources.axaml index cb4f5f6..dd64fc3 100644 --- a/Toolkit.UI.Controls.Avalonia/Themes/ControlResources.axaml +++ b/Toolkit.UI.Controls.Avalonia/Themes/ControlResources.axaml @@ -2,6 +2,66 @@ /Fonts/#FluentSystemIcons-Resizable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +