예제 #1
0
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="collection">元となるコレクション(IList(Of(T)とINotifyPropertyChangedも実装している必要があります)</param>
        /// <param name="dispatcher">UIDispatcher(通常はDispatcherHelper.UIDispatcher)</param>
        public DispatcherCollectionRx(INotifyCollectionChanged collection, Dispatcher dispatcher)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            if (!(collection is IList <T>))
            {
                throw new ArgumentException("collectionはIList<T>を実装している必要があります");
            }

            if (!(collection is INotifyPropertyChanged))
            {
                throw new ArgumentException("collectionはINotifyPropertyChangedを実装している必要があります");
            }

            _souceAsIList = (IList <T>)collection;

            Dispatcher = dispatcher;
            CollectionChangedDispatcherPriority = DispatcherPriority.Normal;

            _disposables.Add(((INotifyPropertyChanged)collection)
                             .ListenPropertyChanged()
                             .Subscribe(e =>
            {
                if (!Dispatcher.CheckAccess())
                {
                    Dispatcher.Invoke(
                        CollectionChangedDispatcherPriority,
                        (Action)
                        (() => OnPropertyChanged(e.PropertyName)));
                }
                else
                {
                    OnPropertyChanged(e.PropertyName);
                }
            }));

            _disposables.Add(collection
                             .ListenCollectionChanged()
                             .Subscribe(e =>
            {
                if (!Dispatcher.CheckAccess())
                {
                    Dispatcher.Invoke(CollectionChangedDispatcherPriority,
                                      (Action)(() => OnCollectionChanged(e)));
                }
                else
                {
                    OnCollectionChanged(e);
                }
            }));
        }
예제 #2
0
 private static IDisposable CreateSubscription<TModel, TViewModel>(
     INotifyCollectionChanged source, Func<TModel, TViewModel> converter,
     DispatcherCollectionRx<TViewModel> target)
 {
     return source.ListenCollectionChanged(e =>
         DispatcherHelper.UIDispatcher.InvokeAsync(() =>
         {
             if (e.NewItems != null && e.NewItems.Count >= 2)
             {
                 throw new ArgumentException("Too many new items.");
             }
             try
             {
                 switch (e.Action)
                 {
                     case NotifyCollectionChangedAction.Add:
                         if (e.NewItems == null)
                         {
                             throw new ArgumentException("New item is null.");
                         }
                         target.Insert(e.NewStartingIndex, converter((TModel)e.NewItems[0]));
                         break;
                     case NotifyCollectionChangedAction.Move:
                         target.Move(e.OldStartingIndex, e.NewStartingIndex);
                         break;
                     case NotifyCollectionChangedAction.Remove:
                         if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                         {
                             ((IDisposable)target[e.OldStartingIndex]).Dispose();
                         }
                         target.RemoveAt(e.OldStartingIndex);
                         break;
                     case NotifyCollectionChangedAction.Replace:
                         if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                         {
                             ((IDisposable)target[e.NewStartingIndex]).Dispose();
                         }
                         if (e.NewItems == null)
                         {
                             throw new ArgumentException("New item is null.");
                         }
                         target[e.NewStartingIndex] = converter((TModel)e.NewItems[0]);
                         break;
                     case NotifyCollectionChangedAction.Reset:
                         if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                         {
                             // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                             foreach (IDisposable item in target)
                             {
                                 item.Dispose();
                             }
                         }
                         target.Clear();
                         break;
                     default:
                         throw new ArgumentException();
                 }
             }
             catch (ArgumentOutOfRangeException aoex)
             {
                 // collection inconsistent state
                 throw new InvalidOperationException(
                     "Collection state is invalid." + Environment.NewLine +
                     "INDEX OUT OF RANGE - " + e.Action + "[" + typeof(TModel).Name + " -> " +
                     typeof(TViewModel).Name + "]" + Environment.NewLine +
                     "new start: " + e.NewStartingIndex + ", count: " +
                     (e.NewItems == null
                         ? "null"
                         : e.NewItems.Count.ToString(CultureInfo.InvariantCulture)) +
                     Environment.NewLine +
                     "source length: " + ((IList<TModel>)source).Count + ", target length: " + target.Count +
                     ".",
                     aoex);
             }
         }));
 }
예제 #3
0
        private static IDisposable CreateSubscription <TModel, TViewModel>(
            INotifyCollectionChanged source, Func <TModel, TViewModel> converter,
            DispatcherCollectionRx <TViewModel> target)
        {
            bool resetOccured = false;

            return(source
                   .ListenCollectionChanged()
                   .ObserveOn(DispatcherHolder.Dispatcher)
                   .Subscribe(e =>
            {
                if (e.NewItems != null && e.NewItems.Count >= 2)
                {
                    throw new ArgumentException("Too many new items.");
                }
                try
                {
                    switch (e.Action)
                    {
                    case NotifyCollectionChangedAction.Add:
                        target.Insert(e.NewStartingIndex, converter((TModel)e.NewItems[0]));
                        break;

                    case NotifyCollectionChangedAction.Move:
                        target.Move(e.OldStartingIndex, e.NewStartingIndex);
                        break;

                    case NotifyCollectionChangedAction.Remove:
                        if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                        {
                            ((IDisposable)target[e.OldStartingIndex]).Dispose();
                        }
                        target.RemoveAt(e.OldStartingIndex);
                        break;

                    case NotifyCollectionChangedAction.Replace:
                        if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                        {
                            ((IDisposable)target[e.NewStartingIndex]).Dispose();
                        }
                        target[e.NewStartingIndex] = converter((TModel)e.NewItems[0]);
                        break;

                    case NotifyCollectionChangedAction.Reset:
                        if (typeof(IDisposable).IsAssignableFrom(typeof(TViewModel)))
                        {
                            foreach (IDisposable item in target)
                            {
                                item.Dispose();
                            }
                            resetOccured = true;
                        }
                        target.Clear();
                        break;

                    default:
                        throw new ArgumentException();
                    }
                }
                catch (ArgumentOutOfRangeException aoex)
                {
                    throw new InvalidOperationException(
                        "Collection state is invalid." + Environment.NewLine +
                        "INDEX OUT OF RANGE - " + e.Action + "[" + typeof(TModel).Name + " -> " +
                        typeof(TViewModel).Name + ", reset: " + resetOccured + " ]" + Environment.NewLine +
                        "new start: " + e.NewStartingIndex + ", count: " +
                        (e.NewItems == null ? "null" : e.NewItems.Count.ToString()) + Environment.NewLine +
                        "source length: " + ((IList <TModel>)source).Count + ", target length: " + target.Count +
                        ".",
                        aoex);
                }
            }));
        }