如何观察不可变列表NotifyCollectionChanged?

时间:2016-01-01 09:34:18

标签: c# wpf system.reactive redux reactiveui

我们知道,我们可以使用ObservableCollection来观察集合的变化。

没关系。

但是如何处理ImmutableList改变了?

例如:我有IObservable<ImmutableArray<int>>和这个蒸汽序列可能:

首先:1,2,3,4,5

第二:1,2,3,4,5,6&lt; ----(绑定到视图时可能会遇到一些性能问题。)

第三名:3,4

是否有任何优雅的方式(或某些库)可以转换IObservable<ImmutableArray<int>> to ObservableCollection<int> ?

然后我们可以观察ObservableCollection通知事件:

首先:添加事件1,2,3,4,5

第二:添加事件6,7&lt; ----(很酷!)

第三:删除事件1,2,5,6

非常感谢。

3 个答案:

答案 0 :(得分:2)

这可能是一种天真的做法,但这是你想到的那种事情吗?

source
    .Subscribe(ia =>
    {
        var ia2 = ia.ToArray();
        var adds = ia2.Except(oc).ToArray();
        var removes = oc.Except(ia2).ToArray();
        foreach (var a in adds)
        {
            oc.Add(a);
        }
        foreach (var r in remove)
        {
            oc.Remove(r);
        }
    });

答案 1 :(得分:0)

经过一些研究,我有一个回答我自己的问题。

最佳解决方案应为Levenshtein distance

计算过程大致如下:

  1. 确定插入删除替换成本。 (insert = 1,delete = 1,substitution = 2)

  2. 计算levenshtein距离并得到矩阵。

  3. 用于最短路径和对齐的Backtrace矩阵。 (它非常像A *寻路,在生成矩阵时设置回溯点并在回溯后获得最佳路径)

  4. 因此,这个问题可能会被关闭。

答案 2 :(得分:0)

我实际上写了一个nuget包,可以自动为你做这个

https://github.com/Weingartner/ReactiveCompositeCollections

部分代码使用不可变列表之间的差异来生成ObservableCollection更改事件。

进行差异化的代码使用DiffLib

    public static IObservable<List<DiffElement<T>>> 
        ChangesObservable<T>
         ( this ICompositeList<T> source
         , IEqualityComparer<T>comparer = null 
         )
    {
        return source
            .Items // IObservable<ImmutableList<T>>
            .StartWith(ImmutableList<T>.Empty)
            .Buffer(2, 1).Where(b => b.Count == 2)
            .Select(b =>
                    {
                        var sections = Diff.CalculateSections(b[0], b[1], comparer);
                        var alignment = Diff.AlignElements
                            (b[0], b[1], sections, new BasicReplaceInsertDeleteDiffElementAligner<T>());
                        return alignment.ToList();
                    });
    }

在另一种方法中可以转换为ObservableCollection

    internal ReadOnlyObservableCollection
        ( ICompositeList<T> list
        , System.Collections.ObjectModel.ObservableCollection<T> collection
        , IEqualityComparer<T> eq
        ) : base(collection)
    {
        _List = list;
        _Collection = collection;

        _Disposable = list.ChangesObservable(eq)
            .Subscribe(change =>
            {
                int i = 0;
                foreach (var diff in change)
                {
                    switch (diff.Operation)
                    {
                        case DiffOperation.Match:
                            break;
                        case DiffOperation.Insert:
                            _Collection.Insert(i, diff.ElementFromCollection2.Value);
                            break;
                        case DiffOperation.Delete:
                            _Collection.RemoveAt(i);
                            i--;
                            break;
                        case DiffOperation.Replace:
                            _Collection[i] = diff.ElementFromCollection2.Value;
                            break;
                        case DiffOperation.Modify:
                            _Collection[i] = diff.ElementFromCollection2.Value;
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                    i++;
                }
            });
    }