Beispiel #1
0
        /// <summary>
        /// Creates a collection whose contents will "follow" another
        /// collection; this method is useful for creating ViewModel collections
        /// that are automatically updated when the respective Model collection
        /// is updated.
        /// </summary>
        /// <param name="selector">A Select function that will be run on each
        /// item.</param>
        /// <returns>A new collection whose items are equivalent to
        /// Collection.Select(selector) and will mirror the initial collection.</returns>
        public static ReactiveCollection <TNew> CreateDerivedCollection <T, TNew>(
            this ObservableCollection <T> This,
            Func <T, TNew> selector)
        {
            Contract.Requires(selector != null);
#if !IOS    // Contract.Result is borked in Mono
            Contract.Ensures(Contract.Result <ReactiveCollection <TNew> >().Count == This.Count);
#endif
            var ret = new ReactiveCollection <TNew>(This.Select(selector));

            var coll_changed = new Subject <NotifyCollectionChangedEventArgs>();
            This.CollectionChanged += (o, e) => coll_changed.OnNext(e);

            /* XXX: Ditto as from above
             * var coll_changed = Observable.FromEvent<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
             *  x => This.CollectionChanged += x, x => This.CollectionChanged -= x);
             */

            coll_changed.Subscribe(x => {
                switch (x.Action)
                {
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Replace:
                    // NB: SL4 fills in OldStartingIndex with -1 on Replace :-/
                    int old_index = (x.Action == NotifyCollectionChangedAction.Replace ?
                                     x.NewStartingIndex : x.OldStartingIndex);

                    if (x.OldItems != null)
                    {
                        foreach (object _ in x.OldItems)
                        {
                            ret.RemoveAt(old_index);
                        }
                    }
                    if (x.NewItems != null)
                    {
                        foreach (T item in x.NewItems.Cast <T>())
                        {
                            ret.Insert(x.NewStartingIndex, selector(item));
                        }
                    }
                    break;

                case NotifyCollectionChangedAction.Reset:
                    ret.Clear();
                    break;

                default:
                    break;
                }
            });

            return(ret);
        }