/// <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);