diff --git a/src/ObservableCollections/ICollectionEventDispatcher.cs b/src/ObservableCollections/ICollectionEventDispatcher.cs index 59040bd..c2ccfa0 100644 --- a/src/ObservableCollections/ICollectionEventDispatcher.cs +++ b/src/ObservableCollections/ICollectionEventDispatcher.cs @@ -45,11 +45,11 @@ namespace ObservableCollections } } - internal class DirectCollectionEventDispatcher : ICollectionEventDispatcher + internal class InlineCollectionEventDispatcher : ICollectionEventDispatcher { - public static readonly ICollectionEventDispatcher Instance = new DirectCollectionEventDispatcher(); + public static readonly ICollectionEventDispatcher Instance = new InlineCollectionEventDispatcher(); - DirectCollectionEventDispatcher() + InlineCollectionEventDispatcher() { } diff --git a/src/ObservableCollections/IObservableCollection.cs b/src/ObservableCollections/IObservableCollection.cs index ac650df..78b0d78 100644 --- a/src/ObservableCollections/IObservableCollection.cs +++ b/src/ObservableCollections/IObservableCollection.cs @@ -1,6 +1,5 @@ using ObservableCollections.Internal; using System; -using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; @@ -45,6 +44,7 @@ namespace ObservableCollections void AttachFilter(ISynchronizedViewFilter filter); void ResetFilter(); + ISynchronizedViewList ToViewList(); INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(); INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher); } diff --git a/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs b/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs index 3114d96..f5e45c5 100644 --- a/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs +++ b/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs @@ -10,7 +10,8 @@ namespace ObservableCollections.Internal internal class SynchronizedViewList : ISynchronizedViewList { readonly ISynchronizedView parent; - readonly List listView; + protected readonly List listView; + protected readonly object gate = new object(); public SynchronizedViewList(ISynchronizedView parent) { @@ -24,76 +25,106 @@ namespace ObservableCollections.Internal private void Parent_ViewChanged(SynchronizedViewChangedEventArgs e) { - // event is called inside lock(parent.SyncRoot) - // TODO: invoke in ICollectionEventDispatcher? - switch (e.Action) + lock (gate) { - case NotifyViewChangedAction.Add: // Add or Insert - if (e.NewViewIndex == -1) - { - listView.Add(e.NewView); - } - else - { - listView.Insert(e.NewViewIndex, e.NewView); - } - break; - case NotifyViewChangedAction.Remove: // Remove - if (e.OldViewIndex == -1) // can't gurantee correct remove if index is not provided - { - listView.Remove(e.OldView); - } - else - { - listView.RemoveAt(e.OldViewIndex); - } - break; - case NotifyViewChangedAction.Replace: // Indexer - if (e.NewViewIndex == -1) - { - var index = listView.IndexOf(e.OldView); - listView[index] = e.NewView; - } - else - { - listView[e.NewViewIndex] = e.NewView; - } + switch (e.Action) + { + case NotifyViewChangedAction.Add: // Add or Insert + if (e.NewViewIndex == -1) + { + listView.Add(e.NewView); + } + else + { + listView.Insert(e.NewViewIndex, e.NewView); + } + break; + case NotifyViewChangedAction.Remove: // Remove + if (e.OldViewIndex == -1) // can't gurantee correct remove if index is not provided + { + listView.Remove(e.OldView); + } + else + { + listView.RemoveAt(e.OldViewIndex); + } + break; + case NotifyViewChangedAction.Replace: // Indexer + if (e.NewViewIndex == -1) + { + var index = listView.IndexOf(e.OldView); + listView[index] = e.NewView; + } + else + { + listView[e.NewViewIndex] = e.NewView; + } - break; - case NotifyViewChangedAction.Move: //Remove and Insert - if (e.NewViewIndex == -1) - { - // do nothing - } - else - { - listView.RemoveAt(e.OldViewIndex); - listView.Insert(e.NewViewIndex, e.NewView); - } - break; - case NotifyViewChangedAction.Reset: // Clear - listView.Clear(); - break; - case NotifyViewChangedAction.FilterReset: - listView.Clear(); - foreach (var item in parent) - { - listView.Add(item.View); - } - break; - default: - break; + break; + case NotifyViewChangedAction.Move: //Remove and Insert + if (e.NewViewIndex == -1) + { + // do nothing + } + else + { + listView.RemoveAt(e.OldViewIndex); + listView.Insert(e.NewViewIndex, e.NewView); + } + break; + case NotifyViewChangedAction.Reset: // Clear + listView.Clear(); + break; + case NotifyViewChangedAction.FilterReset: + listView.Clear(); + foreach (var item in parent) + { + listView.Add(item); + } + break; + default: + break; + } + + OnCollectionChanged(e); } } + protected virtual void OnCollectionChanged(in SynchronizedViewChangedEventArgs args) + { + } - public TView this[int index] => listView[index]; + public TView this[int index] + { + get + { + lock (gate) + { + return listView[index]; + } + } + } - public int Count => listView.Count; + public int Count + { + get + { + lock (gate) + { + return listView.Count; + } + } + } public IEnumerator GetEnumerator() { - return listView.GetEnumerator(); + lock (gate) + { + foreach (var item in listView) + { + yield return item; + } + } } IEnumerator IEnumerable.GetEnumerator() @@ -107,73 +138,32 @@ namespace ObservableCollections.Internal } } - - - internal class NotifyCollectionChangedSynchronizedView : + SynchronizedViewList, INotifyCollectionChangedSynchronizedView, - ISynchronizedViewFilter + IList, IList { static readonly PropertyChangedEventArgs CountPropertyChangedEventArgs = new("Count"); static readonly Action raiseChangedEventInvoke = RaiseChangedEvent; - readonly ISynchronizedView parent; - readonly ISynchronizedViewFilter currentFilter; readonly ICollectionEventDispatcher eventDispatcher; - public NotifyCollectionChangedSynchronizedView(ISynchronizedView parent, ICollectionEventDispatcher? eventDispatcher) - { - this.parent = parent; - this.eventDispatcher = eventDispatcher ?? DirectCollectionEventDispatcher.Instance; - currentFilter = parent.Filter; - parent.AttachFilter(this); - } - - public int Count => parent.Count; - public event NotifyCollectionChangedEventHandler? CollectionChanged; public event PropertyChangedEventHandler? PropertyChanged; - public event Action? CollectionStateChanged + public NotifyCollectionChangedSynchronizedView(ISynchronizedView parent, ICollectionEventDispatcher? eventDispatcher) + : base(parent) { - add { parent.CollectionStateChanged += value; } - remove { parent.CollectionStateChanged -= value; } + this.eventDispatcher = eventDispatcher ?? InlineCollectionEventDispatcher.Instance; } - public event NotifyCollectionChangedEventHandler? RoutingCollectionChanged + protected override void OnCollectionChanged(in SynchronizedViewChangedEventArgs args) { - add { parent.RoutingCollectionChanged += value; } - remove { parent.RoutingCollectionChanged -= value; } - } - - public void Dispose() - { - parent.Dispose(); - } - - public IEnumerator GetEnumerator() - { - foreach (var (value, view) in parent) - { - yield return view; - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public bool IsMatch(T value, TView view) => currentFilter.IsMatch(value, view); - public void WhenTrue(T value, TView view) => currentFilter.WhenTrue(value, view); - public void WhenFalse(T value, TView view) => currentFilter.WhenFalse(value, view); - - public void OnCollectionChanged(in SynchronizedViewChangedEventArgs args) - { - currentFilter.OnCollectionChanged(args); - if (CollectionChanged == null && PropertyChanged == null) return; switch (args.Action) { - case NotifyCollectionChangedAction.Add: + case NotifyViewChangedAction.Add: eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Add, args.NewView, args.NewViewIndex) { Collection = this, @@ -182,7 +172,7 @@ namespace ObservableCollections.Internal IsInvokePropertyChanged = true }); break; - case NotifyCollectionChangedAction.Remove: + case NotifyViewChangedAction.Remove: eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Remove, args.OldView, args.OldViewIndex) { Collection = this, @@ -191,7 +181,7 @@ namespace ObservableCollections.Internal IsInvokePropertyChanged = true }); break; - case NotifyCollectionChangedAction.Reset: + case NotifyViewChangedAction.Reset: eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Reset) { Collection = this, @@ -200,7 +190,7 @@ namespace ObservableCollections.Internal IsInvokePropertyChanged = true }); break; - case NotifyCollectionChangedAction.Replace: + case NotifyViewChangedAction.Replace: eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Replace, args.NewView, args.OldView, args.NewViewIndex) { Collection = this, @@ -209,7 +199,7 @@ namespace ObservableCollections.Internal IsInvokePropertyChanged = false }); break; - case NotifyCollectionChangedAction.Move: + case NotifyViewChangedAction.Move: eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Move, args.NewView, args.NewViewIndex, args.OldViewIndex) { Collection = this, @@ -235,30 +225,12 @@ namespace ObservableCollections.Internal self.PropertyChanged?.Invoke(self, CountPropertyChangedEventArgs); } } - } - internal class ListNotifyCollectionChangedSynchronizedView - : NotifyCollectionChangedSynchronizedView - , IList, IReadOnlyList - , IList - { - readonly ObservableList.View view; + // IList, IList implementation - public ListNotifyCollectionChangedSynchronizedView(ObservableList.View parent, ICollectionEventDispatcher? eventDispatcher) - : base(parent, eventDispatcher) + TView IList.this[int index] { - this.view = parent; - } - - public TView this[int index] - { - get - { - lock (view.SyncRoot) - { - return view.list[index].Item2; - } - } + get => ((IReadOnlyList)this)[index]; set => throw new NotSupportedException(); } @@ -282,7 +254,7 @@ namespace ObservableCollections.Internal public bool IsSynchronized => true; - public object SyncRoot => view.SyncRoot; + public object SyncRoot => gate; public void Add(TView item) { @@ -301,11 +273,11 @@ namespace ObservableCollections.Internal public bool Contains(TView item) { - lock (view.SyncRoot) + lock (gate) { - foreach (var listItem in view.list) + foreach (var listItem in listView) { - if (EqualityComparer.Default.Equals(listItem.Item2, item)) + if (EqualityComparer.Default.Equals(listItem, item)) { return true; } @@ -335,12 +307,12 @@ namespace ObservableCollections.Internal public int IndexOf(TView item) { - lock (view.SyncRoot) + lock (gate) { var index = 0; - foreach (var listItem in view.list) + foreach (var listItem in listView) { - if (EqualityComparer.Default.Equals(listItem.Item2, item)) + if (EqualityComparer.Default.Equals(listItem, item)) { return index; } diff --git a/src/ObservableCollections/ObservableList.Views.cs b/src/ObservableCollections/ObservableList.Views.cs index df02e15..b2e0bc0 100644 --- a/src/ObservableCollections/ObservableList.Views.cs +++ b/src/ObservableCollections/ObservableList.Views.cs @@ -14,6 +14,21 @@ namespace ObservableCollections return new View(this, transform); } + public ISynchronizedViewList ToViewList() + { + return CreateView(static x => x).ToViewList(); + } + + public INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged() + { + return CreateView(static x => x).ToNotifyCollectionChanged(); + } + + public INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher) + { + return CreateView(static x => x).ToNotifyCollectionChanged(collectionEventDispatcher); + } + internal sealed class View : ISynchronizedView { public ISynchronizedViewFilter Filter @@ -107,20 +122,19 @@ namespace ObservableCollections } } + public ISynchronizedViewList ToViewList() + { + return new SynchronizedViewList(this); + } + public INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged() { - lock (SyncRoot) - { - return new ListNotifyCollectionChangedSynchronizedView(this, null); - } + return new NotifyCollectionChangedSynchronizedView(this, null); } public INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher) { - lock (SyncRoot) - { - return new ListNotifyCollectionChangedSynchronizedView(this, collectionEventDispatcher); - } + return new NotifyCollectionChangedSynchronizedView(this, collectionEventDispatcher); } public IEnumerator GetEnumerator()