From 83fef5e39969272f94d36681c50b59457bf58d98 Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Tue, 21 May 2024 20:32:42 +0100 Subject: [PATCH] Fixed more edge cases --- Toolkit.Avalonia/ContentControlHandler.cs | 3 + Toolkit.Foundation/Cache.cs | 26 ++++- Toolkit.Foundation/Created.cs | 10 ++ Toolkit.Foundation/CreatedEventArgs.cs | 3 + Toolkit.Foundation/ICache.cs | 9 +- .../IServiceCollectionExtensions.cs | 4 - Toolkit.Foundation/Modified.cs | 7 ++ Toolkit.Foundation/ModifiedEventArgs.cs | 3 + Toolkit.Foundation/NavigateHandler.cs | 21 +++- Toolkit.Foundation/Observable.cs | 2 +- Toolkit.Foundation/ObservableCollection.cs | 96 ++++++++++--------- Toolkit.Foundation/RemoveAndInsertAt.cs | 7 ++ .../RemoveAndInsertAtEventArgs.cs | 3 + Toolkit.Foundation/RemoveAt.cs | 7 ++ Toolkit.Foundation/RemoveAtEventArgs.cs | 3 + Toolkit.Foundation/RemoveEventArgs.cs | 2 + Toolkit.Foundation/Subscription.cs | 9 +- Toolkit.UI.Avalonia/NavigateAction.cs | 1 - 18 files changed, 153 insertions(+), 63 deletions(-) create mode 100644 Toolkit.Foundation/Created.cs create mode 100644 Toolkit.Foundation/CreatedEventArgs.cs create mode 100644 Toolkit.Foundation/Modified.cs create mode 100644 Toolkit.Foundation/ModifiedEventArgs.cs create mode 100644 Toolkit.Foundation/RemoveAndInsertAt.cs create mode 100644 Toolkit.Foundation/RemoveAndInsertAtEventArgs.cs create mode 100644 Toolkit.Foundation/RemoveAt.cs create mode 100644 Toolkit.Foundation/RemoveAtEventArgs.cs diff --git a/Toolkit.Avalonia/ContentControlHandler.cs b/Toolkit.Avalonia/ContentControlHandler.cs index 46f5c62..912fc19 100644 --- a/Toolkit.Avalonia/ContentControlHandler.cs +++ b/Toolkit.Avalonia/ContentControlHandler.cs @@ -54,7 +54,10 @@ public class ContentControlHandler : control.Unloaded += HandleUnloaded; control.DataContext = args.Content; + + contentControl.Content = null; contentControl.Content = control; + await taskCompletionSource.Task; } } diff --git a/Toolkit.Foundation/Cache.cs b/Toolkit.Foundation/Cache.cs index 2b3ae64..1cd3b54 100644 --- a/Toolkit.Foundation/Cache.cs +++ b/Toolkit.Foundation/Cache.cs @@ -1,5 +1,5 @@ using System.Collections; -using System.Collections.Concurrent; +using System.Collections.Immutable; using System.Reactive.Disposables; namespace Toolkit.Foundation; @@ -10,6 +10,12 @@ public class Cache(IDisposer disposer, { private readonly SortedSet cache = new(comparer); + public int IndexOf(TValue value) + { + ImmutableSortedSet hashSet = cache.ToImmutableSortedSet(comparer); + return hashSet.IndexOf(value); + } + public void Add(TValue value) { if (value is null) @@ -21,6 +27,17 @@ public class Cache(IDisposer disposer, cache.Add(value); } + public bool TryGetValue(TValue key, out TValue? value) + { + if (cache.TryGetValue(key, out value)) + { + return true; + } + + value = default; + return false; + } + public void Clear() => cache.Clear(); public IEnumerator GetEnumerator() => cache.GetEnumerator(); @@ -30,14 +47,15 @@ public class Cache(IDisposer disposer, public bool Remove(TValue value) => cache.Remove(value); } -public class Cache : +public class Cache(IDisposer disposer, + IComparer comparer) : ICache where TKey : notnull where TValue : notnull { - private readonly ConcurrentDictionary cache = new(); + private readonly SortedList cache = new(comparer); public void Add(TKey key, TValue value) @@ -49,6 +67,8 @@ public class Cache : public bool ContainsKey(TKey key) => cache.ContainsKey(key); + public int IndexOf(TKey key) => cache.IndexOfKey(key); + public IEnumerator> GetEnumerator() => cache.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/Toolkit.Foundation/Created.cs b/Toolkit.Foundation/Created.cs new file mode 100644 index 0000000..0d00928 --- /dev/null +++ b/Toolkit.Foundation/Created.cs @@ -0,0 +1,10 @@ +namespace Toolkit.Foundation; + +public record Created +{ + public static CreatedEventArgs As(TValue value) => + new(value); + + public static CreatedEventArgs As() where TValue : new() => + new(new TValue()); +} diff --git a/Toolkit.Foundation/CreatedEventArgs.cs b/Toolkit.Foundation/CreatedEventArgs.cs new file mode 100644 index 0000000..cdb03eb --- /dev/null +++ b/Toolkit.Foundation/CreatedEventArgs.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record CreatedEventArgs(TValue Value); diff --git a/Toolkit.Foundation/ICache.cs b/Toolkit.Foundation/ICache.cs index 2143da6..ae7bedb 100644 --- a/Toolkit.Foundation/ICache.cs +++ b/Toolkit.Foundation/ICache.cs @@ -7,7 +7,11 @@ public interface ICache : void Clear(); + int IndexOf(TValue value); + bool Remove(TValue value); + + bool TryGetValue(TValue key, out TValue? value); } public interface ICache : @@ -17,13 +21,14 @@ public interface ICache : where TValue : notnull { - void Add(TKey key, - TValue value); + void Add(TKey key, TValue value); void Clear(); bool ContainsKey(TKey key); + int IndexOf(TKey key); + bool Remove(TKey key); bool TryGetValue(TKey key, out TValue? value); diff --git a/Toolkit.Foundation/IServiceCollectionExtensions.cs b/Toolkit.Foundation/IServiceCollectionExtensions.cs index 370643c..caa5095 100644 --- a/Toolkit.Foundation/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/IServiceCollectionExtensions.cs @@ -1,9 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.FileProviders.Physical; -using Microsoft.Extensions.Hosting; -using System.Text.Json; namespace Toolkit.Foundation; diff --git a/Toolkit.Foundation/Modified.cs b/Toolkit.Foundation/Modified.cs new file mode 100644 index 0000000..d7b32e7 --- /dev/null +++ b/Toolkit.Foundation/Modified.cs @@ -0,0 +1,7 @@ +namespace Toolkit.Foundation; + +public record Modified +{ + public static ModifiedEventArgs As(TValue oldValue, TValue newValue) => + new(oldValue, newValue); +} diff --git a/Toolkit.Foundation/ModifiedEventArgs.cs b/Toolkit.Foundation/ModifiedEventArgs.cs new file mode 100644 index 0000000..a678ca9 --- /dev/null +++ b/Toolkit.Foundation/ModifiedEventArgs.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record ModifiedEventArgs(TValue OldView, TValue NewValue); diff --git a/Toolkit.Foundation/NavigateHandler.cs b/Toolkit.Foundation/NavigateHandler.cs index 0310642..e976f02 100644 --- a/Toolkit.Foundation/NavigateHandler.cs +++ b/Toolkit.Foundation/NavigateHandler.cs @@ -8,12 +8,25 @@ public class NavigateHandler(NamedComponent scope, { public Task Handle(NavigateEventArgs args) { - INavigationScope? navigationScope; - if (args.Scope == "self" && args.Sender is IServiceProviderRequired requireServiceProvider) + INavigationScope? navigationScope = null; + if (args.Scope is "self" || args.Scope is "new") { - navigationScope = requireServiceProvider.Provider.GetRequiredService(); + if (args.Sender is IServiceProviderRequired requireServiceProvider) + { + if (args.Scope is "self") + { + navigationScope = requireServiceProvider.Provider.GetRequiredService(); + } + + if (args.Scope is "new") + { + IServiceScope serviceScope = requireServiceProvider.Provider.CreateScope(); + navigationScope = serviceScope.ServiceProvider.GetRequiredService(); + } + } } - else + + if (navigationScope is null) { ComponentScopeDescriptor? descriptor = componentScopeProvider.Get(args.Scope ?? scope.Name); navigationScope = descriptor?.Services?.GetRequiredService(); diff --git a/Toolkit.Foundation/Observable.cs b/Toolkit.Foundation/Observable.cs index 0a3e62d..884dd49 100644 --- a/Toolkit.Foundation/Observable.cs +++ b/Toolkit.Foundation/Observable.cs @@ -63,7 +63,7 @@ public partial class Observable : public virtual Task OnDeactivating() => Task.CompletedTask; - public void Dispose() + public virtual void Dispose() { GC.SuppressFinalize(this); Disposer.Dispose(this); diff --git a/Toolkit.Foundation/ObservableCollection.cs b/Toolkit.Foundation/ObservableCollection.cs index 6beebc8..5ec43a8 100644 --- a/Toolkit.Foundation/ObservableCollection.cs +++ b/Toolkit.Foundation/ObservableCollection.cs @@ -24,12 +24,14 @@ public partial class ObservableCollection : IPublisherRequired, IDisposerRequired, INotificationHandler>, + INotificationHandler>, + INotificationHandler>, INotificationHandler>, INotificationHandler>, INotificationHandler>, INotificationHandler> where TItem : - notnull + IDisposable { private readonly System.Collections.ObjectModel.ObservableCollection collection = []; @@ -111,12 +113,6 @@ public partial class ObservableCollection : set => SetItem(index, value); } - public void ResetAndAddRange(Action> args) - { - Clear(); - args.Invoke(this); - } - object? IList.this[int index] { get => collection[index]; @@ -136,18 +132,13 @@ public partial class ObservableCollection : } } - public TItem Add() => + public TItem Add() => Add(null, false); public TItem Add(params object?[] parameters) - where T : TItem => Add(null, false, parameters); + where T : TItem => Add(false, parameters); - public TItem Add(IDisposable? owner, - params object?[] parameters) - where T : TItem => Add(owner, false, parameters); - - public TItem Add(IDisposable? owner = null, - bool scope = false, + public TItem Add(bool scope = false, params object?[] parameters) where T : TItem @@ -162,17 +153,6 @@ public partial class ObservableCollection : T? item = factory is not null ? factory.Create(parameters) : Factory.Create(parameters); Add(item); - if (owner is not null) - { - Disposer.Add(owner, Disposable.Create(() => - { - if (item is IRemovable) - { - Remove(item); - } - })); - } - return item; } @@ -213,6 +193,20 @@ public partial class ObservableCollection : } } + public void BeginAggregation() + { + if (this.GetAttribute() is AggerateAttribute attribute) + { + if (attribute.Mode == AggerateMode.Reset) + { + Clear(); + } + + object? key = this.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key; + Publisher.PublishUI(OnPrepareAggregation(key)); + } + } + public void Clear() { clearing = true; @@ -220,6 +214,7 @@ public partial class ObservableCollection : foreach (TItem item in this.ToList()) { Disposer.Dispose(item); + Disposer.Remove(this, item); } ClearItems(); @@ -250,20 +245,6 @@ public partial class ObservableCollection : Disposer.Dispose(this); } - public void BeginAggregation() - { - if (this.GetAttribute() is AggerateAttribute attribute) - { - if (attribute.Mode == AggerateMode.Reset) - { - Clear(); - } - - object? key = this.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key; - Publisher.PublishUI(OnPrepareAggregation(key)); - } - } - public IEnumerator GetEnumerator() => collection.GetEnumerator(); @@ -323,6 +304,27 @@ public partial class ObservableCollection : return Task.CompletedTask; } + public Task Handle(RemoveAtEventArgs args) + { + if (args.Index >= 0 && args.Index <= Count - 1) + { + RemoveAt(args.Index); + } + + return Task.CompletedTask; + } + + public Task Handle(RemoveAndInsertAtEventArgs args) + { + if (args.OldIndex >= 0 && args.OldIndex <= Count - 1 && args.Value is TItem item) + { + RemoveAt(args.OldIndex); + Insert(args.NewIndex, item); + } + + return Task.CompletedTask; + } + public int IndexOf(TItem item) => collection.IndexOf(item); @@ -385,8 +387,10 @@ public partial class ObservableCollection : { return false; } - + Disposer.Dispose(item); + Disposer.Remove(this, item); + RemoveItem(index); return true; @@ -419,6 +423,12 @@ public partial class ObservableCollection : return true; } + public void ResetAndAddRange(Action> args) + { + Clear(); + args.Invoke(this); + } + protected virtual void ClearItems() => collection.Clear(); @@ -439,7 +449,7 @@ public partial class ObservableCollection : } })); - collection.Insert(index, item); + collection.Insert(index > Count ? Count : index, item); } protected virtual IAggerate OnPrepareAggregation(object? key) => @@ -476,7 +486,7 @@ public partial class ObservableCollection(IServiceProvider p IMediator mediator, IPublisher publisher, ISubscription subscriber, IDisposer disposer) : ObservableCollection(provider, factory, mediator, publisher, subscriber, disposer) - where TViewModel : notnull + where TViewModel : IDisposable { [ObservableProperty] private TValue? value; diff --git a/Toolkit.Foundation/RemoveAndInsertAt.cs b/Toolkit.Foundation/RemoveAndInsertAt.cs new file mode 100644 index 0000000..0b44d06 --- /dev/null +++ b/Toolkit.Foundation/RemoveAndInsertAt.cs @@ -0,0 +1,7 @@ +namespace Toolkit.Foundation; + +public record RemoveAndInsertAt +{ + public static RemoveAndInsertAtEventArgs As(int oldIndex, int newIndex, TValue value) => + new(oldIndex, newIndex, value); +} \ No newline at end of file diff --git a/Toolkit.Foundation/RemoveAndInsertAtEventArgs.cs b/Toolkit.Foundation/RemoveAndInsertAtEventArgs.cs new file mode 100644 index 0000000..362bb1c --- /dev/null +++ b/Toolkit.Foundation/RemoveAndInsertAtEventArgs.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record RemoveAndInsertAtEventArgs(int OldIndex, int NewIndex, TValue Value); diff --git a/Toolkit.Foundation/RemoveAt.cs b/Toolkit.Foundation/RemoveAt.cs new file mode 100644 index 0000000..8de3297 --- /dev/null +++ b/Toolkit.Foundation/RemoveAt.cs @@ -0,0 +1,7 @@ +namespace Toolkit.Foundation; + +public record RemoveAt +{ + public static RemoveAtEventArgs As(int index) => + new(index); +} diff --git a/Toolkit.Foundation/RemoveAtEventArgs.cs b/Toolkit.Foundation/RemoveAtEventArgs.cs new file mode 100644 index 0000000..6403a64 --- /dev/null +++ b/Toolkit.Foundation/RemoveAtEventArgs.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record RemoveAtEventArgs(int Index); diff --git a/Toolkit.Foundation/RemoveEventArgs.cs b/Toolkit.Foundation/RemoveEventArgs.cs index e689d4c..6ba0b5b 100644 --- a/Toolkit.Foundation/RemoveEventArgs.cs +++ b/Toolkit.Foundation/RemoveEventArgs.cs @@ -1,3 +1,5 @@ namespace Toolkit.Foundation; public record RemoveEventArgs(TValue Value); + +public record RemoveAndInsertEventArgs(TValue Value); \ No newline at end of file diff --git a/Toolkit.Foundation/Subscription.cs b/Toolkit.Foundation/Subscription.cs index 299b9d9..02e06a1 100644 --- a/Toolkit.Foundation/Subscription.cs +++ b/Toolkit.Foundation/Subscription.cs @@ -21,7 +21,7 @@ public class Subscription(SubscriptionCollection subscriptions, return collection; }); - disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, argumentType))); + disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, subscriptionKey))); } } } @@ -51,10 +51,9 @@ public class Subscription(SubscriptionCollection subscriptions, private void RemoveSubscriber(object subscriber, - Type argumentType) + string key) { - string subscriptionKey = $"{argumentType}"; - if (subscriptions.TryGetValue(subscriptionKey, out List? subscribers)) + if (subscriptions.TryGetValue(key, out List? subscribers)) { for (int i = subscribers.Count - 1; i >= 0; i--) { @@ -66,7 +65,7 @@ public class Subscription(SubscriptionCollection subscriptions, if (subscribers.Count == 0) { - subscriptions.TryRemove(subscriptionKey, out _); + subscriptions.TryRemove(key, out _); } } } diff --git a/Toolkit.UI.Avalonia/NavigateAction.cs b/Toolkit.UI.Avalonia/NavigateAction.cs index be04ddc..017632e 100644 --- a/Toolkit.UI.Avalonia/NavigateAction.cs +++ b/Toolkit.UI.Avalonia/NavigateAction.cs @@ -1,6 +1,5 @@ using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; using Avalonia.Metadata; using Avalonia.Xaml.Interactivity; using Toolkit.Foundation;