예제 #1
0
        void sectionCollectionChanged(int section, IList <NotifyCollectionChangedEventArgs> xs)
        {
            if (xs.Count == 0)
            {
                return;
            }

            var resetOnlyNotification = new [] { new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset) };

            this.Log().Info("Changed contents: [{0}]", String.Join(",", xs.Select(x => x.Action.ToString())));

            if (xs.Any(x => x.Action == NotifyCollectionChangedAction.Reset))
            {
                this.Log().Info("About to call ReloadData");
                adapter.ReloadData();

                didPerformUpdates.OnNext(resetOnlyNotification);
                return;
            }

            var updates           = xs.Select(ea => Tuple.Create(ea, getChangedIndexes(ea))).ToList();
            var allChangedIndexes = updates.SelectMany(u => u.Item2).ToList();

            // Detect if we're changing the same cell more than
            // once - if so, issue a reset and be done

            if (allChangedIndexes.Count != allChangedIndexes.Distinct().Count())
            {
                this.Log().Info("Detected a dupe in the changelist. Issuing Reset");
                adapter.ReloadData();

                didPerformUpdates.OnNext(resetOnlyNotification);
                return;
            }

            this.Log().Info("Beginning update");
            adapter.PerformBatchUpdates(() => {
                foreach (var update in updates.AsEnumerable().Reverse())
                {
                    var changeAction   = update.Item1.Action;
                    var changedIndexes = update.Item2;

                    switch (changeAction)
                    {
                    case NotifyCollectionChangedAction.Add:
                        doUpdate(adapter.InsertItems, changedIndexes, section);
                        break;

                    case NotifyCollectionChangedAction.Remove:
                        doUpdate(adapter.DeleteItems, changedIndexes, section);
                        break;

                    case NotifyCollectionChangedAction.Replace:
                        doUpdate(adapter.ReloadItems, changedIndexes, section);
                        break;

                    case NotifyCollectionChangedAction.Move:
                        // NB: ReactiveList currently only supports single-item
                        // moves
                        var ea = update.Item1;
                        this.Log().Info("Calling MoveRow: {0}-{1} => {0}{2}", section, ea.OldStartingIndex, ea.NewStartingIndex);

                        adapter.MoveItem(
                            NSIndexPath.FromRowSection(ea.OldStartingIndex, section),
                            NSIndexPath.FromRowSection(ea.NewStartingIndex, section));
                        break;

                    default:
                        this.Log().Info("Unknown Action: {0}", changeAction);
                        break;
                    }
                }

                this.Log().Info("Ending update");
                didPerformUpdates.OnNext(xs);
            });
        }
예제 #2
0
        private void ApplyPendingChanges()
        {
            try
            {
                List <NotifyCollectionChangedEventArgs> allEventArgs = new List <NotifyCollectionChangedEventArgs>();

                this.Log().Debug("Beginning update");
                adapter.PerformBatchUpdates(() =>
                {
                    if (this.Log().Level >= LogLevel.Debug)
                    {
                        this.Log().Debug("The pending changes (in order received) are:");

                        foreach (var pendingChange in pendingChanges)
                        {
                            this.Log().Debug(
                                "Section {0}: Action={1}, OldStartingIndex={2}, NewStartingIndex={3}, OldItems.Count={4}, NewItems.Count={5}",
                                pendingChange.Item1,
                                pendingChange.Item2.Action,
                                pendingChange.Item2.OldStartingIndex,
                                pendingChange.Item2.NewStartingIndex,
                                pendingChange.Item2.OldItems == null ? "null" : pendingChange.Item2.OldItems.Count.ToString(),
                                pendingChange.Item2.NewItems == null ? "null" : pendingChange.Item2.NewItems.Count.ToString());
                        }
                    }

                    foreach (var sectionedUpdates in pendingChanges.GroupBy(x => x.Item1))
                    {
                        var section = sectionedUpdates.First().Item1;

                        this.Log().Debug("Processing updates for section {0}", section);

                        var allSectionEas = sectionedUpdates
                                            .Select(x => x.Item2)
                                            .ToList();

                        if (allSectionEas.Any(x => x.Action == NotifyCollectionChangedAction.Reset))
                        {
                            this.Log().Debug("Section {0} included a reset notification, so reloading that section.", section);
#if UNIFIED
                            adapter.ReloadSections(new NSIndexSet((nuint)section));
#else
                            adapter.ReloadSections(new NSIndexSet((uint)section));
#endif
                            continue;
                        }

                        var updates = allSectionEas
                                      .SelectMany(GetUpdatesForEvent)
                                      .ToList();

                        if (this.Log().Level >= LogLevel.Debug)
                        {
                            this.Log().Debug(
                                "Updates for section {0}: {1}",
                                section,
                                updates
                                .Aggregate(
                                    new StringBuilder(),
                                    (current, next) =>
                            {
                                if (current.Length > 0)
                                {
                                    current.Append(":");
                                }

                                return(current.Append(next));
                            },
                                    x => x.ToString()));
                        }

                        var normalizedUpdates = IndexNormalizer.Normalize(updates);

                        if (this.Log().Level >= LogLevel.Debug)
                        {
                            this.Log().Debug(
                                "Normalized updates for section {0}: {1}",
                                section,
                                normalizedUpdates
                                .Aggregate(
                                    new StringBuilder(),
                                    (current, next) =>
                            {
                                if (current.Length > 0)
                                {
                                    current.Append(":");
                                }

                                return(current.Append(next));
                            },
                                    x => x.ToString()));
                        }

                        foreach (var normalizedUpdate in normalizedUpdates)
                        {
                            switch (normalizedUpdate.Type)
                            {
                            case UpdateType.Add:
                                DoUpdate(adapter.InsertItems, new[] { normalizedUpdate.Index }, section);
                                break;

                            case UpdateType.Delete:
                                DoUpdate(adapter.DeleteItems, new[] { normalizedUpdate.Index }, section);
                                break;

                            default:
                                throw new NotSupportedException();
                            }
                        }
                    }
                }, () =>
                {
                    this.Log().Debug("Ending update");
                    didPerformUpdates.OnNext(allEventArgs);
                });
            }
            finally
            {
                pendingChanges.Clear();
                isCollectingChanges = false;
            }
        }
예제 #3
0
        public CommonReactiveSource(
            IUICollViewAdapter <TUIView, TUIViewCell> adapter,
            IEnumerable <ISectionInformation <TUIView, TUIViewCell> > sectionInfo)
        {
            this.adapter     = adapter;
            this.sectionInfo = sectionInfo.ToList();

            for (int i = 0; i < this.sectionInfo.Count; i++)
            {
                var current = this.sectionInfo[i].Collection;

                var section = i;
                var disp    = current.Changed.Buffer(TimeSpan.FromMilliseconds(250), RxApp.MainThreadScheduler).Subscribe(xs => {
                    if (xs.Count == 0)
                    {
                        return;
                    }

                    var resetOnlyNotification = new [] { new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset) };

                    this.Log().Info("Changed contents: [{0}]", String.Join(",", xs.Select(x => x.Action.ToString())));
                    if (xs.Any(x => x.Action == NotifyCollectionChangedAction.Reset))
                    {
                        this.Log().Info("About to call ReloadData");
                        adapter.ReloadData();
                        didPerformUpdates.OnNext(resetOnlyNotification);
                        return;
                    }

                    var updates           = xs.Select(ea => Tuple.Create(ea, getChangedIndexes(ea))).ToList();
                    var allChangedIndexes = updates.SelectMany(u => u.Item2).ToList();
                    // Detect if we're changing the same cell more than
                    // once - if so, issue a reset and be done
                    if (allChangedIndexes.Count != allChangedIndexes.Distinct().Count())
                    {
                        this.Log().Info("Detected a dupe in the changelist. Issuing Reset");
                        adapter.ReloadData();
                        didPerformUpdates.OnNext(resetOnlyNotification);
                        return;
                    }

                    this.Log().Info("Beginning update");
                    adapter.PerformBatchUpdates(() => {
                        foreach (var update in updates.AsEnumerable().Reverse())
                        {
                            var changeAction   = update.Item1.Action;
                            var changedIndexes = update.Item2;
                            switch (changeAction)
                            {
                            case NotifyCollectionChangedAction.Add:
                                doUpdate(adapter.InsertItems, changedIndexes, section);
                                break;

                            case NotifyCollectionChangedAction.Remove:
                                doUpdate(adapter.DeleteItems, changedIndexes, section);
                                break;

                            case NotifyCollectionChangedAction.Replace:
                                doUpdate(adapter.ReloadItems, changedIndexes, section);
                                break;

                            case NotifyCollectionChangedAction.Move:
                                // NB: ReactiveList currently only supports single-item
                                // moves
                                var ea = update.Item1;
                                this.Log().Info("Calling MoveRow: {0}-{1} => {0}{2}", section, ea.OldStartingIndex, ea.NewStartingIndex);

                                adapter.MoveItem(
                                    NSIndexPath.FromRowSection(ea.OldStartingIndex, section),
                                    NSIndexPath.FromRowSection(ea.NewStartingIndex, section));
                                break;

                            default:
                                this.Log().Info("Unknown Action: {0}", changeAction);
                                break;
                            }
                        }

                        this.Log().Info("Ending update");
                        didPerformUpdates.OnNext(xs);
                    });
                });

                innerDisp.Add(disp);
            }
        }