diff --git a/Toolkit.Avalonia/Toolkit.Avalonia.csproj b/Toolkit.Avalonia/Toolkit.Avalonia.csproj index 795e2a3..a972a43 100644 --- a/Toolkit.Avalonia/Toolkit.Avalonia.csproj +++ b/Toolkit.Avalonia/Toolkit.Avalonia.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/Toolkit.Foundation/Cache.cs b/Toolkit.Foundation/Cache.cs index d067ed4..d649dbf 100644 --- a/Toolkit.Foundation/Cache.cs +++ b/Toolkit.Foundation/Cache.cs @@ -2,7 +2,7 @@ namespace Toolkit.Foundation; -public class Cache(IComparer? comparer = default) : +public class Cache(IComparer comparer) : ICache { private readonly List items = []; @@ -15,15 +15,23 @@ public class Cache(IComparer? comparer = default) : public void Add(TValue item) { - int index = items.BinarySearch(item, comparer); - if (index < 0) - { - index = ~index; - } + int index = FindInsertIndex(item); items.Insert(index, item); } - public void Clear() => items.Clear(); + public void Clear() => + items.Clear(); + + public bool Contains(TValue item) + { + int index = items.IndexOf(item); + if (index >= 0) + { + return true; + } + + return false; + } public IEnumerator GetEnumerator() => items.GetEnumerator(); @@ -31,33 +39,23 @@ public class Cache(IComparer? comparer = default) : IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator(); public int IndexOf(TValue item) => - items.BinarySearch(item, comparer); + items.IndexOf(item); public bool Remove(TValue item) { - int index = items.BinarySearch(item, comparer); + int index = items.IndexOf(item); if (index >= 0) { items.RemoveAt(index); return true; } - return false; - } - - public bool Contains(TValue key) - { - int index = items.BinarySearch(key, comparer); - if (index >= 0) - { - return true; - } return false; } public bool TryGetValue(TValue key, out TValue? item) { - int index = items.BinarySearch(key, comparer); + int index = items.IndexOf(key); if (index >= 0) { item = items[index]; @@ -67,6 +65,33 @@ public class Cache(IComparer? comparer = default) : item = default; return false; } + + private int FindInsertIndex(TValue item) + { + int low = 0, high = items.Count - 1; + + while (low <= high) + { + int mid = (low + high) / 2; + int cmp = comparer.Compare(items[mid], item); + + if (cmp < 0) + { + low = mid + 1; + } + else + { + high = mid - 1; + } + } + + while (low < items.Count && comparer.Compare(items[low], item) == 0) + { + low++; + } + + return low; + } } public class Cache(IComparer comparer) : @@ -123,8 +148,19 @@ public class Cache(IComparer comparer) : public void Clear() => items.Clear(); + public bool Contains(TKey key) + { + int index = items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0); + if (index >= 0) + { + items.RemoveAt(index); + return true; + } + return false; + } + public IEnumerator> GetEnumerator() => - items.GetEnumerator(); + items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -157,18 +193,6 @@ public class Cache(IComparer comparer) : value = default; return false; } - - public bool Contains(TKey key) - { - int index = items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0); - if (index >= 0) - { - items.RemoveAt(index); - return true; - } - return false; - } - private class KeyValuePairComparer(IComparer comparer) : IComparer> { diff --git a/Toolkit.Foundation/ObservableCollection.cs b/Toolkit.Foundation/ObservableCollection.cs index fad0037..e3daf3f 100644 --- a/Toolkit.Foundation/ObservableCollection.cs +++ b/Toolkit.Foundation/ObservableCollection.cs @@ -1,5 +1,4 @@ using CommunityToolkit.Mvvm.ComponentModel; -using Microsoft.Extensions.DependencyInjection; using System.Collections; using System.Collections.Specialized; using System.Reactive.Disposables; @@ -36,17 +35,18 @@ public partial class ObservableCollection : { private readonly System.Collections.ObjectModel.ObservableCollection collection = []; - private bool clearing; + private readonly Queue pendingEvents = []; + [ObservableProperty] + private bool activated; + private bool clearing; [ObservableProperty] private bool initialized; - [ObservableProperty] - private int selectedIndex = 0; - [ObservableProperty] private TItem? selectedItem; + private bool supressSelection; public ObservableCollection(IServiceProvider provider, IServiceFactory factory, IMediator mediator, @@ -243,22 +243,36 @@ public partial class ObservableCollection : public Task Handle(RemoveEventArgs args) { - foreach (TItem item in this.ToList()) + if (Activated) { - if (args.Value is not null && args.Value.Equals(item)) + foreach (TItem item in this.ToList()) { - Remove(item); + if (args.Value is not null && args.Value.Equals(item)) + { + Remove(item); + } } } + else + { + pendingEvents.Enqueue(args); + } return Task.CompletedTask; } public Task Handle(CreateEventArgs args) { - if (args.Value is TItem item) + if (Activated) { - Add(item); + if (args.Value is TItem item) + { + Add(item); + } + } + else + { + pendingEvents.Enqueue(args); } return Task.CompletedTask; @@ -266,34 +280,60 @@ public partial class ObservableCollection : public Task Handle(InsertEventArgs args) { - if (args.Value is TItem item) + if (Activated) { - Insert(args.Index, item); - - if (item is ISelectable selectable) + if (args.Value is TItem item) { - if (selectable.Selected) + Insert(args.Index, item); + if (item is ISelectable newSelection) { - SelectedItem = item; - SelectedIndex = IndexOf(item); + if (newSelection.Selected) + { + foreach (ISelectable oldSelection in this.OfType().Where(x => x is + ISelectable oldSelection && oldSelection != newSelection)) + { + oldSelection.Selected = false; + } + + SelectedItem = item; + } } } } + else + { + pendingEvents.Enqueue(args); + } return Task.CompletedTask; } public Task Handle(MoveToEventArgs args) { - Move(args.OldIndex, args.NewIndex); + if (Activated) + { + Move(args.OldIndex, args.NewIndex); + } + else + { + pendingEvents.Enqueue(args); + } + return Task.CompletedTask; } public Task Handle(MoveEventArgs args) { - if (args.Value is TItem item) + if (Activated) { - Move(args.Index, item); + if (args.Value is TItem item) + { + Move(args.Index, item); + } + } + else + { + pendingEvents.Enqueue(args); } return Task.CompletedTask; @@ -301,9 +341,16 @@ public partial class ObservableCollection : public Task Handle(ReplaceEventArgs args) { - if (args.Value is TItem item) + if (Activated) { - Replace(args.Index, item); + if (args.Value is TItem item) + { + Replace(args.Index, item); + } + } + else + { + pendingEvents.Enqueue(args); } return Task.CompletedTask; @@ -311,10 +358,18 @@ public partial class ObservableCollection : public Task Handle(RemoveAtEventArgs args) { - if (args.Index >= 0 && args.Index <= Count - 1) + if (Activated) { - RemoveAt(args.Index); + if (args.Index >= 0 && args.Index <= Count - 1) + { + RemoveAt(args.Index); + } } + else + { + pendingEvents.Enqueue(args); + } + return Task.CompletedTask; } @@ -343,12 +398,12 @@ public partial class ObservableCollection : } public TItem Insert(int index = 0, - params object?[] parameters) + params object?[] parameters) where T : TItem { T? item = Factory.Create(parameters); - InsertItem(0, item); + InsertItem(index, item); return item; } @@ -377,9 +432,7 @@ public partial class ObservableCollection : if (item is ISelectable selectable) { selected = selectable.Selected; - SelectedItem = default; - SelectedIndex = -1; } RemoveItem(oldIndex); @@ -387,9 +440,7 @@ public partial class ObservableCollection : if (selected) { - SelectedIndex = newIndex; SelectedItem = item; - if (item is ISelectable selectable2) { selectable2.Selected = true; @@ -413,11 +464,23 @@ public partial class ObservableCollection : return true; } - public virtual Task OnActivated() => - Task.CompletedTask; + public virtual Task OnActivated() + { + Activated = true; + while (pendingEvents.Count > 0) + { + object current = pendingEvents.Dequeue(); + Handle((dynamic)current); + } - public virtual Task OnDeactivated() => - Task.CompletedTask; + return Task.CompletedTask; + } + + public virtual Task OnDeactivated() + { + Activated = false; + return Task.CompletedTask; + } public virtual Task OnDeactivating() => Task.CompletedTask; @@ -509,20 +572,8 @@ public partial class ObservableCollection : private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) => CollectionChanged?.Invoke(this, args); - partial void OnSelectedIndexChanged(int oldValue, int newValue) - { - if (oldValue >= 0 && oldValue <= this.Count - 1 && this[oldValue] is ISelectable removed) - { - removed.Selected = false; - } - - if (newValue >= 0 && newValue <= this.Count - 1 && this[newValue] is ISelectable added) - { - added.Selected = true; - } - } - - partial void OnSelectedItemChanged(TItem? oldValue, TItem? newValue) + partial void OnSelectedItemChanged(TItem? oldValue, + TItem? newValue) { if (SelectedItem is not null && !SelectedItem.Equals(oldValue)) { diff --git a/Toolkit.UI.Avalonia/Toolkit.UI.Avalonia.csproj b/Toolkit.UI.Avalonia/Toolkit.UI.Avalonia.csproj index 7753f8f..3519c81 100644 --- a/Toolkit.UI.Avalonia/Toolkit.UI.Avalonia.csproj +++ b/Toolkit.UI.Avalonia/Toolkit.UI.Avalonia.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/Toolkit.UI.Controls.Avalonia/Toolkit.UI.Controls.Avalonia.csproj b/Toolkit.UI.Controls.Avalonia/Toolkit.UI.Controls.Avalonia.csproj index 9154e5d..4172de1 100644 --- a/Toolkit.UI.Controls.Avalonia/Toolkit.UI.Controls.Avalonia.csproj +++ b/Toolkit.UI.Controls.Avalonia/Toolkit.UI.Controls.Avalonia.csproj @@ -12,7 +12,7 @@ - +