protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { _listeners.Dispose(); if (typeof(IDisposable).IsAssignableFrom(typeof(T))) { foreach (var i in _list.OfType <IDisposable>()) { i.Dispose(); } } } _disposed = true; }
public static ReadOnlyDispatcherCollection <TViewModel> CreateReadOnlyDispatcherCollection <TModel, TViewModel>( [NotNull] IList <TModel> source, [NotNull] Func <TModel, TViewModel> converter, [NotNull] Dispatcher dispatcher) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (converter == null) { throw new ArgumentNullException(nameof(converter)); } if (dispatcher == null) { throw new ArgumentNullException(nameof(dispatcher)); } if (!(source is INotifyCollectionChanged sourceAsNotifyCollection)) { throw new ArgumentException("sourceがINotifyCollectionChangedを実装していません"); } var initCollection = new ObservableCollection <TViewModel>(); foreach (var model in source) { initCollection.Add(converter(model)); } var target = new DispatcherCollection <TViewModel>(initCollection, dispatcher); var result = new ReadOnlyDispatcherCollection <TViewModel>(target); var collectionChangedListener = new CollectionChangedEventListener(sourceAsNotifyCollection); result.EventListeners.Add(collectionChangedListener); collectionChangedListener.RegisterHandler((sender, e) => { if (e == null) { throw new ArgumentNullException(nameof(e)); } switch (e.Action) { case NotifyCollectionChangedAction.Add: var vm = converter((TModel)e.NewItems?[0]); InvokeOnDispatcher(() => target.Insert(e.NewStartingIndex, vm), dispatcher); break; case NotifyCollectionChangedAction.Move: InvokeOnDispatcher(() => target.Move(e.OldStartingIndex, e.NewStartingIndex), dispatcher); break; case NotifyCollectionChangedAction.Remove: if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel))) { ((IDisposable)target[e.OldStartingIndex])?.Dispose(); } InvokeOnDispatcher(() => target.RemoveAt(e.OldStartingIndex), dispatcher); break; case NotifyCollectionChangedAction.Replace: if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel))) { ((IDisposable)target[e.NewStartingIndex])?.Dispose(); } var replaceVm = converter((TModel)e.NewItems?[0]); InvokeOnDispatcher(() => target[e.NewStartingIndex] = replaceVm, dispatcher); break; case NotifyCollectionChangedAction.Reset: if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel))) { foreach (var item in target.OfType <IDisposable>()) { item.Dispose(); } } InvokeOnDispatcher(target.Clear, dispatcher); break; default: throw new ArgumentException(); } }); return(result); }