/// <summary> /// constructor /// </summary> /// <param name="source">source collection</param> /// <param name="filter">filter function</param> public FilteredReadOnlyObservableCollection(TCollection source, Func <TElement, bool> filter) { Source = source; Filter = filter; Initialize(); { // propertychanged CollectionUtilities.ObserveElementPropertyChanged <TCollection, TElement>(source) .Subscribe(x => { var index = source.IndexOf(x.Sender); var filteredIndex = IndexList[index]; var isTarget = Filter(x.Sender); if (isTarget && filteredIndex == null) { // add AppearNewItem(index); } else if (!isTarget && filteredIndex.HasValue) { // remove DisappearItem(index); IndexList[index] = null; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, x.Sender, filteredIndex.Value)); } }) .AddTo(Subscription); } { // collection changed(support single changed only) source.CollectionChangedAsObservable() .Subscribe(x => { switch (x.Action) { case NotifyCollectionChangedAction.Add: // appear IndexList.Insert(x.NewStartingIndex, null); if (Filter(x.NewItems.Cast <TElement>().Single())) { AppearNewItem(x.NewStartingIndex); } break; case NotifyCollectionChangedAction.Move: throw new NotSupportedException("Move is not supported"); case NotifyCollectionChangedAction.Remove: var removedIndex = IndexList[x.OldStartingIndex]; if (removedIndex.HasValue) { DisappearItem(x.OldStartingIndex); IndexList.RemoveAt(x.OldStartingIndex); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, x.OldItems.Cast <TElement>().Single(), removedIndex.Value)); } else { IndexList.RemoveAt(x.OldStartingIndex); } break; case NotifyCollectionChangedAction.Replace: var index = IndexList[x.NewStartingIndex]; var isTarget = Filter(x.NewItems.Cast <TElement>().Single()); if (index == null && isTarget) { // add AppearNewItem(x.NewStartingIndex); } else if (index.HasValue && isTarget) { // replace InnerCollection[index.Value] = x.NewItems.Cast <TElement>().Single(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, x.NewItems.Cast <TElement>().Single(), x.OldItems.Cast <TElement>().Single(), index.Value)); } else if (index.HasValue && !isTarget) { // remove DisappearItem(x.NewStartingIndex); IndexList[x.NewStartingIndex] = null; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, x.OldItems.Cast <TElement>().Single(), index.Value)); } break; case NotifyCollectionChangedAction.Reset: Initialize(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); break; default: throw new InvalidOperationException(); } }) .AddTo(Subscription); } }
/// <summary> /// Observe collection element's IObservable sequence. /// </summary> /// <typeparam name="TElement">Collection element type</typeparam> /// <typeparam name="TProperty">Type of observable property element</typeparam> /// <param name="source">Source collection</param> /// <param name="propertySelector">IObservable selection expression</param> /// <returns>IObservable sequence sequence</returns> public static IObservable <PropertyPack <TElement, TProperty> > ObserveElementObservableProperty <TElement, TProperty>(this IFilteredReadOnlyObservableCollection <TElement> source, Expression <Func <TElement, IObservable <TProperty> > > propertySelector) where TElement : class, INotifyPropertyChanged => CollectionUtilities.ObserveElementObservableProperty(source, propertySelector);
/// <summary> /// Observe collection element's PropertyChanged event. /// </summary> /// <typeparam name="TElement">Type of Element</typeparam> /// <param name="source">source collection</param> /// <returns>PropertyChanged event stream.</returns> public static IObservable <SenderEventArgsPair <TElement, PropertyChangedEventArgs> > ObserveElementPropertyChanged <TElement>(this IFilteredReadOnlyObservableCollection <TElement> source) where TElement : class, INotifyPropertyChanged => CollectionUtilities.ObserveElementPropertyChanged <IFilteredReadOnlyObservableCollection <TElement>, TElement>(source);
/// <summary> /// Observe collection element's property. /// </summary> /// <typeparam name="TElement">Type of element</typeparam> /// <typeparam name="TProperty">Type of property</typeparam> /// <param name="source">Data source</param> /// <param name="propertySelector">Property selection expression</param> /// <param name="isPushCurrentValueAtFirst">Push current value on first subscribe</param> /// <returns>Property sequence</returns> public static IObservable <PropertyPack <TElement, TProperty> > ObserveElementProperty <TElement, TProperty>(this IFilteredReadOnlyObservableCollection <TElement> source, Expression <Func <TElement, TProperty> > propertySelector, bool isPushCurrentValueAtFirst = true) where TElement : class, INotifyPropertyChanged => CollectionUtilities.ObserveElementProperty(source, propertySelector, isPushCurrentValueAtFirst);