コード例 #1
0
        public static ReadOnlyDispatcherCollectionRx<TViewModel> CreateReadOnlyDispatcherCollectionRx
            <TModel, TViewModel>(ObservableSynchronizedCollectionEx<TModel> source, Func<TModel, TViewModel> converter,
                Dispatcher dispatcher, DispatcherPriority priority = DispatcherPriority.Normal)
        {
            if (source == null) throw new ArgumentNullException("source");

            if (!DispatcherHelper.UIDispatcher.CheckAccess())
            {
                throw new ArgumentException("This method must be called on the Dispatcher thread.");
            }

            var sourceAsNotifyCollection = source as INotifyCollectionChanged;
            if (sourceAsNotifyCollection == null)
                throw new ArgumentException("sourceがINotifyCollectionChangedを実装していません");

            var initCollection = new ObservableCollection<TViewModel>();
            var target = new DispatcherCollectionRx<TViewModel>(initCollection, dispatcher)
            {
                CollectionChangedDispatcherPriority = priority
            };
            var result = new ReadOnlyDispatcherCollectionRx<TViewModel>(target);

            source.SynchronizedToArray(array =>
            {
                foreach (var model in array)
                {
                    initCollection.Add(converter(model));
                }
                result.Disposables.Add(CreateSubscription(sourceAsNotifyCollection, converter, target));
            });
            return result;
        }
コード例 #2
0
        public ReadOnlyDispatcherCollectionRx(DispatcherCollectionRx <T> collection)
            : base(collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            _collection = collection;

            _disposables.Add(_collection.ListenPropertyChanged(OnPropertyChanged));
            _disposables.Add(_collection.ListenCollectionChanged(OnCollectionChanged));
        }
コード例 #3
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);
             }
         }));
 }
コード例 #4
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);
                }
            }));
        }