コード例 #1
0
        public IObservable <IChangeSet <T> > Run()
        {
            return(Observable.Create <IChangeSet <T> >(observer =>
            {
                var locker = new object();
                var orginal = new ChangeAwareList <T>();
                var target = new ChangeAwareList <T>();

                var changed = _source.Synchronize(locker).Select(changes =>
                {
                    if (_resetThreshold > 1)
                    {
                        orginal.Clone(changes);
                    }

                    return changes.TotalChanges > _resetThreshold && _comparer != null ? Reset(orginal, target) : Process(target, changes);
                });
                var resort = _resort.Synchronize(locker).Select(changes => Reorder(target));
                var changeComparer = _comparerObservable.Synchronize(locker).Select(comparer => ChangeComparer(target, comparer));

                return changed.Merge(resort).Merge(changeComparer)
                .Where(changes => changes.Count != 0)
                .SubscribeSafe(observer);
            }));
        }
コード例 #2
0
        private IChangeSet <TDestination> Process(ChangeAwareList <TDestination> transformed, IChangeSet <TSource> source)
        {
            //TODO: This is very inefficient as it flattens range operation
            //need to find a means of re-forming ranges
            var children = source.Unified().SelectMany(change =>
            {
                var many = _manyselector(change.Current);
                return(many.Select(m => new TransformedItem <TDestination>(change.Reason, m)));
            });

            foreach (var child in children)
            {
                switch (child.Reason)
                {
                case ListChangeReason.Add:
                    transformed.Add(child.Current);
                    break;

                case ListChangeReason.Replace:
                    transformed.Remove(child.Previous.Value);
                    transformed.Add(child.Current);
                    break;

                case ListChangeReason.Remove:
                    transformed.Remove(child.Current);
                    break;

                case ListChangeReason.Clear:
                    transformed.Clear();
                    break;
                }
            }
            return(transformed.CaptureChanges());
        }
コード例 #3
0
ファイル: Pager.cs プロジェクト: mgnslndh/DynamicData
        public IObservable <IPageChangeSet <T> > Run()
        {
            return(Observable.Create <IPageChangeSet <T> >(observer =>
            {
                var locker = new object();
                var all = new List <T>();
                var paged = new ChangeAwareList <T>();

                IPageRequest parameters = new PageRequest(0, 25);

                var requestStream = _requests
                                    .Synchronize(locker)
                                    .Select(request =>
                {
                    parameters = request;
                    return CheckParametersAndPage(all, paged, request);
                });

                var datachanged = _source
                                  .Synchronize(locker)
                                  .Select(changes => Page(all, paged, parameters, changes));

                return requestStream.Merge(datachanged)
                .Where(changes => changes != null && changes.Count != 0)
                .SubscribeSafe(observer);
            }));
        }
コード例 #4
0
ファイル: Virtualiser.cs プロジェクト: mgnslndh/DynamicData
        public IObservable <IVirtualChangeSet <T> > Run()
        {
            return(Observable.Create <IVirtualChangeSet <T> >(observer =>
            {
                var locker = new object();
                var all = new List <T>();
                var virtualised = new ChangeAwareList <T>();

                IVirtualRequest parameters = new VirtualRequest(0, 25);

                var requestStream = _requests
                                    .Synchronize(locker)
                                    .Select(request =>
                {
                    parameters = request;
                    return CheckParamsAndVirtualise(all, virtualised, request);
                });

                var datachanged = _source
                                  .Synchronize(locker)
                                  .Select(changes => Virtualise(all, virtualised, parameters, changes));

                //TODO: Remove this shared state stuff ie. _parameters
                return requestStream.Merge(datachanged)
                .Where(changes => changes != null && changes.Count != 0)
                .Select(changes => new VirtualChangeSet <T>(changes, new VirtualResponse(virtualised.Count, parameters.StartIndex, all.Count)))
                .SubscribeSafe(observer);
            }));
        }
コード例 #5
0
        private IChangeSet <T> ProcessImpl(ChangeAwareList <T> target, IChangeSet <T> changes)
        {
            foreach (var change in changes)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var current = change.Item.Current;
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    var ordered = change.Range.OrderBy(t => t, _comparer).ToList();
                    if (target.Count == 0)
                    {
                        target.AddRange(ordered);
                    }
                    else
                    {
                        ordered.ForEach(item => Insert(target, item));
                    }
                    break;
                }

                case ListChangeReason.Replace:
                {
                    var current = change.Item.Current;
                    //TODO: check whether an item should stay in the same position
                    //i.e. update and move
                    Remove(target, change.Item.Previous.Value);
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.Remove:
                {
                    var current = change.Item.Current;
                    Remove(target, current);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    target.RemoveMany(change.Range);
                    break;
                }

                case ListChangeReason.Clear:
                {
                    target.Clear();
                    break;
                }
                }
            }
            return(target.CaptureChanges());
        }
コード例 #6
0
        private IChangeSet <T> Reset(ChangeAwareList <T> original, ChangeAwareList <T> target)
        {
            var sorted = original.OrderBy(t => t, _comparer).ToList();

            target.Clear();
            target.AddRange(sorted);
            return(target.CaptureChanges());
        }
コード例 #7
0
 public IObservable <IChangeSet <TDestination> > Run()
 {
     return(Observable.Create <IChangeSet <TDestination> >(observer =>
     {
         var transformed = new ChangeAwareList <TDestination>();
         return _source.Select(changes => Process(transformed, changes)).NotEmpty().SubscribeSafe(observer);
     }));
 }
コード例 #8
0
ファイル: Pager.cs プロジェクト: kiwipiet/DynamicData
        private IChangeSet <T> Page(List <T> all, ChangeAwareList <T> paged, IChangeSet <T> changeset = null)
        {
            if (changeset != null)
            {
                all.Clone(changeset);
            }

            var previous = paged;

            int pages = CalculatePages(all);
            int page  = _parameters.Page > pages ? pages : _parameters.Page;
            int skip  = _parameters.Size * (page - 1);

            var current = all.Skip(skip)
                          .Take(_parameters.Size)
                          .ToList();

            var adds    = current.Except(previous);
            var removes = previous.Except(current);

            paged.RemoveMany(removes);

            adds.ForEach(t =>
            {
                var index = current.IndexOf(t);
                paged.Insert(index, t);
            });

            var startIndex = skip;

            var moves = changeset.EmptyIfNull()
                        .Where(change => change.Reason == ListChangeReason.Moved &&
                               change.MovedWithinRange(startIndex, startIndex + _parameters.Size));

            foreach (var change in moves)
            {
                //check whether an item has moved within the same page
                var currentIndex  = change.Item.CurrentIndex - startIndex;
                var previousIndex = change.Item.PreviousIndex - startIndex;
                paged.Move(previousIndex, currentIndex);
            }

            //find replaces [Is this ever the case that it can be reached]
            for (int i = 0; i < current.Count; i++)
            {
                var currentItem  = current[i];
                var previousItem = previous[i];

                if (ReferenceEquals(currentItem, previousItem))
                {
                    continue;
                }

                var index = paged.IndexOf(currentItem);
                paged.Move(i, index);
            }
            return(paged.CaptureChanges());
        }
コード例 #9
0
ファイル: Pager.cs プロジェクト: mgnslndh/DynamicData
        private PageChangeSet <T> CheckParametersAndPage(List <T> all, ChangeAwareList <T> paged, IPageRequest request)
        {
            if (request == null || request.Page < 0 || request.Size < 1)
            {
                return(null);
            }

            return(Page(all, paged, request));
        }
コード例 #10
0
ファイル: Virtualiser.cs プロジェクト: mgnslndh/DynamicData
        private IChangeSet <T> CheckParamsAndVirtualise(List <T> all, ChangeAwareList <T> virtualised, IVirtualRequest request)
        {
            if (request == null || request.StartIndex < 0 || request.Size < 1)
            {
                return(null);
            }

            return(Virtualise(all, virtualised, request));
        }
コード例 #11
0
        private IChangeSet <T> ChangeComparer(ChangeAwareList <T> target, IComparer <T> comparer)
        {
            _comparer = comparer;
            var sorted = target.OrderBy(t => t, _comparer).ToList();

            target.Clear();
            target.AddRange(sorted);
            return(target.CaptureChanges());
        }
コード例 #12
0
        private IChangeSet <T> Virtualise(List <T> all, ChangeAwareList <T> virtualised, IVirtualRequest request)
        {
            if (request == null || request.StartIndex < 0 || request.Size < 1)
            {
                return(null);
            }

            _parameters = request;
            return(Virtualise(all, virtualised));
        }
コード例 #13
0
 private int GetInsertPositionLinear(ChangeAwareList <T> target, T item)
 {
     for (var i = 0; i < target.Count; i++)
     {
         if (_comparer.Compare(item, target[i]) < 0)
         {
             return(i);
         }
     }
     return(target.Count);
 }
コード例 #14
0
 public IObservable <IChangeSet <T> > Run()
 {
     return(Observable.Create <IChangeSet <T> >(observer =>
     {
         var filtered = new ChangeAwareList <T>();
         return _source.Select(changes =>
         {
             filtered.Filter(changes, _predicate);
             return filtered.CaptureChanges();
         }).NotEmpty().SubscribeSafe(observer);
     }));
 }
コード例 #15
0
        private int GetInsertPositionBinary(ChangeAwareList <T> target, T item)
        {
            int index       = target.BinarySearch(item, _comparer);
            int insertIndex = ~index;

            //sort is not returning uniqueness
            if (insertIndex < 0)
            {
                throw new SortException("Binary search has been specified, yet the sort does not yeild uniqueness");
            }
            return(insertIndex);
        }
コード例 #16
0
        private IChangeSet <T> Process(ChangeAwareList <T> target, IChangeSet <T> changes)
        {
            //if all removes and not Clear, then more efficient to try clear range
            if (changes.TotalChanges == changes.Removes && changes.All(c => c.Reason != ListChangeReason.Clear) && changes.Removes > 1)
            {
                var removed = changes.Unified().Select(u => u.Current);
                target.RemoveMany(removed);
                return(target.CaptureChanges());
            }

            return(ProcessImpl(target, changes));
        }
コード例 #17
0
ファイル: Virtualiser.cs プロジェクト: mgnslndh/DynamicData
        private IChangeSet <T> Virtualise(List <T> all, ChangeAwareList <T> virtualised, IVirtualRequest request, IChangeSet <T> changeset = null)
        {
            if (changeset != null)
            {
                all.Clone(changeset);
            }

            var previous = virtualised;

            var current = all.Skip(request.StartIndex)
                          .Take(request.Size)
                          .ToList();

            var adds    = current.Except(previous);
            var removes = previous.Except(current);

            virtualised.RemoveMany(removes);

            adds.ForEach(t =>
            {
                var index = current.IndexOf(t);
                virtualised.Insert(index, t);
            });

            var moves = changeset.EmptyIfNull()
                        .Where(change => change.Reason == ListChangeReason.Moved &&
                               change.MovedWithinRange(request.StartIndex, request.StartIndex + request.Size));

            foreach (var change in moves)
            {
                //check whether an item has moved within the same page
                var currentIndex  = change.Item.CurrentIndex - request.StartIndex;
                var previousIndex = change.Item.PreviousIndex - request.StartIndex;
                virtualised.Move(previousIndex, currentIndex);
            }

            //find replaces [Is this ever the case that it can be reached]
            for (var i = 0; i < current.Count; i++)
            {
                var currentItem  = current[i];
                var previousItem = previous[i];

                if (ReferenceEquals(currentItem, previousItem))
                {
                    continue;
                }

                var index = virtualised.IndexOf(currentItem);
                virtualised.Move(i, index);
            }
            return(virtualised.CaptureChanges());
        }
コード例 #18
0
        public IObservable <IChangeSet <TValue> > Run()
        {
            return(Observable.Create <IChangeSet <TValue> >(observer =>
            {
                var valueCounters = new Dictionary <TValue, int>();
                var result = new ChangeAwareList <TValue>();

                return _source.Transform(t => new ItemWithValue <T, TValue>(t, _valueSelector(t)))
                .Select(changes => Process(valueCounters, result, changes))
                .NotEmpty()
                .SubscribeSafe(observer);
            }));
        }
コード例 #19
0
        private int GetCurrentPosition(ChangeAwareList <T> target, T item)
        {
            int index = _sortOptions == SortOptions.UseBinarySearch
                ? target.BinarySearch(item, _comparer)
                : target.IndexOf(item);

            if (index < 0)
            {
                throw new SortException("Current item cannot be found");
            }

            return(index);
        }
コード例 #20
0
ファイル: GroupOn.cs プロジェクト: kiwipiet/DynamicData
        public IObservable <IChangeSet <IGroup <TObject, TGroupKey> > > Run()
        {
            return(Observable.Create <IChangeSet <IGroup <TObject, TGroupKey> > >(observer =>
            {
                var groupings = new ChangeAwareList <IGroup <TObject, TGroupKey> >();
                var groupCache = new Dictionary <TGroupKey, Group <TObject, TGroupKey> >();

                return _source.Transform(t => new ItemWithValue <TObject, TGroupKey>(t, _groupSelector(t)))
                .Select(changes => Process(groupings, groupCache, changes))
                .DisposeMany()               //dispose removes as the grouping is disposable
                .NotEmpty()
                .SubscribeSafe(observer);
            }));
        }
コード例 #21
0
ファイル: Pager.cs プロジェクト: kiwipiet/DynamicData
        private IChangeSet <T> Page(List <T> all, ChangeAwareList <T> paged, IPageRequest request)
        {
            if (request == null || request.Page < 0 || request.Size < 1)
            {
                return(null);
            }

            if (request.Size == _parameters.Size && request.Page == _parameters.Page)
            {
                return(null);
            }

            _parameters = request;
            return(Page(all, paged));
        }
コード例 #22
0
        private IChangeSet <IGroup <TObject, TGroupKey> > Regroup(ChangeAwareList <IGroup <TObject, TGroupKey> > result,
                                                                  IDictionary <TGroupKey, Group <TObject, TGroupKey> > groupCollection,
                                                                  IReadOnlyCollection <ItemWithValue <TObject, TGroupKey> > currentItems)
        {
            //TODO: We need to update ItemWithValue>

            foreach (var itemWithValue in currentItems)
            {
                var currentGroupKey = itemWithValue.Value;
                var newGroupKey     = _groupSelector(itemWithValue.Item);
                if (newGroupKey.Equals(currentGroupKey))
                {
                    continue;
                }


                //remove from the old group
                var currentGroupLookup = GetCache(groupCollection, currentGroupKey);
                var currentGroupCache  = currentGroupLookup.Group;
                currentGroupCache.Edit(innerList => innerList.Remove(itemWithValue.Item));

                if (currentGroupCache.List.Count == 0)
                {
                    groupCollection.Remove(currentGroupKey);
                    result.Remove(currentGroupCache);
                }

                //Mark the old item with the new cache group
                itemWithValue.Value = newGroupKey;

                //add to the new group
                var newGroupLookup = GetCache(groupCollection, newGroupKey);
                var newGroupCache  = newGroupLookup.Group;
                newGroupCache.Edit(innerList => innerList.Add(itemWithValue.Item));

                if (newGroupLookup.WasCreated)
                {
                    result.Add(newGroupCache);
                }
            }

            return(result.CaptureChanges());
        }
コード例 #23
0
        public IObservable <IChangeSet <T> > Run()
        {
            return(Observable.Create <IChangeSet <T> >(observer =>
            {
                var locker = new object();
                var all = new List <T>();
                var virtualised = new ChangeAwareList <T>();

                var requestStream = _requests
                                    .Synchronize(locker)
                                    .Select(request => Virtualise(all, virtualised, request));

                var datachanged = _source
                                  .Synchronize(locker)
                                  .Select(changes => Virtualise(all, virtualised, changes));

                return requestStream.Merge(datachanged)
                .Where(changes => changes != null && changes.Count != 0)
                .SubscribeSafe(observer);
            }));
        }
コード例 #24
0
        public IObservable <IChangeSet <T> > Run()
        {
            return(Observable.Create <IChangeSet <T> >(observer =>
            {
                var allWithMatch = new List <ItemWithMatch>();
                var all = new List <T>();
                var filtered = new ChangeAwareList <T>();
                var locker = new object();

                //requery wehn controller either fires changed or requery event
                var refresher = _predicates.Synchronize(locker)
                                .Select(predicate =>
                {
                    Requery(predicate, allWithMatch, all, filtered);
                    var changed = filtered.CaptureChanges();
                    return changed;
                });

                var shared = _source.Synchronize(locker).Publish();

                //take current filter state of all items
                var updateall = shared.Synchronize(locker)
                                .Transform(t => new ItemWithMatch(t, _predicate(t)))
                                .Subscribe(allWithMatch.Clone);

                //filter result list
                var filter = shared.Synchronize(locker)
                             .Select(changes =>
                {
                    filtered.Filter(changes, _predicate);
                    var changed = filtered.CaptureChanges();
                    return changed;
                });

                var subscriber = refresher.Merge(filter).NotEmpty().SubscribeSafe(observer);

                return new CompositeDisposable(updateall, subscriber, shared.Connect());
            }));
        }
コード例 #25
0
        private IChangeSet <T> Reorder(ChangeAwareList <T> target)
        {
            int index  = -1;
            var sorted = target.OrderBy(t => t, _comparer).ToList();

            foreach (var item in sorted)
            {
                index++;

                var existing = target[index];
                //if item is in the same place,
                if (ReferenceEquals(item, existing))
                {
                    continue;
                }

                //Cannot use binary search as Resort is implicit of a mutable change
                var old = target.IndexOf(item);
                target.Move(old, index);
            }

            return(target.CaptureChanges());
        }
コード例 #26
0
        public IObservable <IChangeSet <IGroup <TObject, TGroupKey> > > Run()
        {
            return(Observable.Create <IChangeSet <IGroup <TObject, TGroupKey> > >(observer =>
            {
                var groupings = new ChangeAwareList <IGroup <TObject, TGroupKey> >();
                var groupCache = new Dictionary <TGroupKey, Group <TObject, TGroupKey> >();

                var itemsWithGroup = _source
                                     .Transform(t => new ItemWithValue <TObject, TGroupKey>(t, _groupSelector(t)))
                                     .AsObservableList();

                var locker = new object();
                var shared = itemsWithGroup.Connect().Synchronize(locker).Publish();

                var grouper = shared
                              .Select(changes => Process(groupings, groupCache, changes));

                IObservable <IChangeSet <IGroup <TObject, TGroupKey> > > regrouper;
                if (_regrouper == null)
                {
                    regrouper = Observable.Never <IChangeSet <IGroup <TObject, TGroupKey> > >();
                }
                else
                {
                    regrouper = _regrouper.Synchronize(locker)
                                .CombineLatest(shared.ToCollection(), (_, collection) => Regroup(groupings, groupCache, collection));
                }

                var publisher = grouper.Merge(regrouper)
                                .DisposeMany() //dispose removes as the grouping is disposable
                                .NotEmpty()
                                .SubscribeSafe(observer);

                return new CompositeDisposable(itemsWithGroup, publisher, shared.Connect());
            }));
        }
コード例 #27
0
ファイル: Transformer.cs プロジェクト: mgnslndh/DynamicData
        private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            transformed.EnsureCapacityFor(changes);

            foreach (var item in changes)
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                {
                    var change = item.Item;
                    if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count)
                    {
                        transformed.Add(_containerFactory(change.Current));
                    }
                    else
                    {
                        transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                    }
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    transformed.AddOrInsertRange(item.Range.Select(_containerFactory), item.Range.Index);
                    break;
                }

                case ListChangeReason.Replace:
                {
                    var change = item.Item;
                    if (change.CurrentIndex == change.PreviousIndex)
                    {
                        transformed[change.CurrentIndex] = _containerFactory(change.Current);
                    }
                    else
                    {
                        transformed.RemoveAt(change.PreviousIndex);
                        transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                    }

                    break;
                }

                case ListChangeReason.Remove:
                {
                    var  change   = item.Item;
                    bool hasIndex = change.CurrentIndex >= 0;

                    if (hasIndex)
                    {
                        transformed.RemoveAt(item.Item.CurrentIndex);
                    }
                    else
                    {
                        var toremove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t));

                        if (toremove != null)
                        {
                            transformed.Remove(toremove);
                        }
                    }

                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    if (item.Range.Index >= 0)
                    {
                        transformed.RemoveRange(item.Range.Index, item.Range.Count);
                    }
                    else
                    {
                        var toremove = transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray();
                        transformed.RemoveMany(toremove);
                    }

                    break;
                }

                case ListChangeReason.Clear:
                {
                    //i.e. need to store transformed reference so we can correctly clear
                    var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed);
                    transformed.ClearOrRemoveMany(toClear);

                    break;
                }

                case ListChangeReason.Moved:
                {
                    var  change   = item.Item;
                    bool hasIndex = change.CurrentIndex >= 0;
                    if (!hasIndex)
                    {
                        throw new UnspecifiedIndexException("Cannot move as an index was not specified");
                    }

                    var collection = transformed as IExtendedList <TransformedItemContainer>;
                    if (collection != null)
                    {
                        collection.Move(change.PreviousIndex, change.CurrentIndex);
                    }
                    else
                    {
                        var current = transformed[change.PreviousIndex];
                        transformed.RemoveAt(change.PreviousIndex);
                        transformed.Insert(change.CurrentIndex, current);
                    }
                    break;
                }
                }
            }
        }
コード例 #28
0
ファイル: GroupOn.cs プロジェクト: kiwipiet/DynamicData
        private IChangeSet <IGroup <TObject, TGroupKey> > Process(ChangeAwareList <IGroup <TObject, TGroupKey> > result, IDictionary <TGroupKey, Group <TObject, TGroupKey> > groupCollection, IChangeSet <ItemWithValue <TObject, TGroupKey> > changes)
        {
            //TODO.This flattened enumerator is inefficient as range operations are lost.
            //maybe can infer within each grouping whether we can regroup i.e. Another enumerator!!!

            foreach (var grouping in changes.Unified().GroupBy(change => change.Current.Value))
            {
                //lookup group and if created, add to result set
                var currentGroup = grouping.Key;
                var lookup       = GetCache(groupCollection, currentGroup);
                var groupCache   = lookup.Group;

                if (lookup.WasCreated)
                {
                    result.Add(groupCache);
                }

                //start a group edit session, so all changes are batched
                groupCache.Edit(
                    list =>
                {
                    //iterate through the group's items and process
                    foreach (var change in grouping)
                    {
                        switch (change.Reason)
                        {
                        case ListChangeReason.Add:
                            {
                                list.Add(change.Current.Item);
                                break;
                            }

                        case ListChangeReason.Replace:
                            {
                                var previousItem  = change.Previous.Value.Item;
                                var previousGroup = change.Previous.Value.Value;

                                //check whether an item changing has resulted in a different group
                                if (previousGroup.Equals(currentGroup))
                                {
                                    //find and replace
                                    var index   = list.IndexOf(previousItem);
                                    list[index] = change.Current.Item;
                                }
                                else
                                {
                                    //add to new group
                                    list.Add(change.Current.Item);

                                    //remove from old group
                                    groupCollection.Lookup(previousGroup)
                                    .IfHasValue(g =>
                                    {
                                        g.Edit(oldList => oldList.Remove(previousItem));
                                        if (g.List.Count != 0)
                                        {
                                            return;
                                        }
                                        groupCollection.Remove(g.GroupKey);
                                        result.Remove(g);
                                    });
                                }

                                break;
                            }

                        case ListChangeReason.Remove:
                            {
                                list.Remove(change.Current.Item);
                                break;
                            }

                        case ListChangeReason.Clear:
                            {
                                list.Clear();
                                break;
                            }
                        }
                    }
                });

                if (groupCache.List.Count == 0)
                {
                    groupCollection.Remove(groupCache.GroupKey);
                    result.Remove(groupCache);
                }
            }
            return(result.CaptureChanges());
        }
コード例 #29
0
        //TODO: Need to account for re-evaluate (as it is not mutually excluse to clear and replace)

        private void Requery(Func <T, bool> predicate, List <ItemWithMatch> allWithMatch, List <T> all, ChangeAwareList <T> filtered)
        {
            _predicate = predicate;

            var newState = allWithMatch.Select(item =>
            {
                var match    = _predicate(item.Item);
                var wasMatch = item.IsMatch;

                //reflect filtered state
                if (item.IsMatch != match)
                {
                    item.IsMatch = match;
                }

                return(new
                {
                    Item = item,
                    IsMatch = match,
                    WasMatch = wasMatch
                });
            }).ToList();

            //reflect items which are no longer matched
            var noLongerMatched = newState.Where(state => !state.IsMatch && state.WasMatch).Select(state => state.Item.Item);

            filtered.RemoveMany(noLongerMatched);

            //reflect new matches in the list
            var newMatched = newState.Where(state => state.IsMatch && !state.WasMatch).Select(state => state.Item.Item);

            filtered.AddRange(newMatched);
        }
コード例 #30
0
        private IChangeSet <TValue> Process(Dictionary <TValue, int> valueCounters, ChangeAwareList <TValue> result,
                                            IChangeSet <ItemWithValue <T, TValue> > changes)
        {
            Action <TValue> addAction = value => valueCounters.Lookup(value)
                                        .IfHasValue(count => valueCounters[value] = count + 1)
                                        .Else(() =>
            {
                valueCounters[value] = 1;
                result.Add(value);
            });

            Action <TValue> removeAction = value =>
            {
                var counter = valueCounters.Lookup(value);
                if (!counter.HasValue)
                {
                    return;
                }

                //decrement counter
                var newCount = counter.Value - 1;
                valueCounters[value] = newCount;
                if (newCount != 0)
                {
                    return;
                }

                //if there are none, then remove and notify
                result.Remove(value);
            };

            foreach (var change in changes)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var value = change.Item.Current.Value;
                    addAction(value);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    change.Range.Select(item => item.Value).ForEach(addAction);
                    break;
                }

                //	case ListChangeReason.Evaluate:
                case ListChangeReason.Replace:
                {
                    var value    = change.Item.Current.Value;
                    var previous = change.Item.Previous.Value.Value;
                    if (value.Equals(previous))
                    {
                        continue;
                    }

                    removeAction(previous);
                    addAction(value);
                    break;
                }

                case ListChangeReason.Remove:
                {
                    var previous = change.Item.Current.Value;
                    removeAction(previous);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    change.Range.Select(item => item.Value).ForEach(removeAction);
                    break;
                }

                case ListChangeReason.Clear:
                {
                    result.Clear();
                    valueCounters.Clear();
                    break;
                }
                }
            }
            return(result.CaptureChanges());
        }