Wpf 合并两个可观察的集合并使用Rx绑定到Listbox

Wpf 合并两个可观察的集合并使用Rx绑定到Listbox,wpf,system.reactive,reactiveui,Wpf,System.reactive,Reactiveui,我需要将2个ObservableCollection合并为一个,并将其绑定到网格,并需要实时更新以流向网格。例如 ObservableCollection<int> First = new ObservableCollection<int>(); ObservableCollection<int> Second = new ObservableCollection<int>(); //Some Rx Psuedo Code (p.s. this

我需要将2个ObservableCollection合并为一个,并将其绑定到网格,并需要实时更新以流向网格。例如

ObservableCollection<int> First = new ObservableCollection<int>();
ObservableCollection<int> Second  = new ObservableCollection<int>();

//Some Rx Psuedo Code (p.s. this is not the actual code, this is where i need help)
{
    var guicollection = First
        .Where(i => i%2)
        .Merge(Second.Where(i => i % 3)).ToCollection();
}

listBox1.ItemsSource = guidcollection;

First.Add(1);
First.Add(2);
First.Add(3);
First.Add(4);
First.Add(5);
Second.Add(1);
Second.Add(2);
Second.Add(3);
Second.Add(4);

// Now the guicollection should have the following items 2,4 from FirstCollection
// and 3 from second collection
ObservableCollection First=新的ObservableCollection();
ObservableCollection Second=新的ObservableCollection();
//一些Rx Psuedo代码(请注意,这不是实际代码,这是我需要帮助的地方)
{
var guicollection=First
.其中(i=>i%2)
.Merge(Second.Where(i=>i%3)).ToCollection();
}
listBox1.ItemsSource=guidcollection;
第一,加入第(1)款;
第一,加入第(2)款;
第一,加入第(3)款;
第一,增加第(4)款;
第一,加入(5);
第二条增加第(1)款;
第二条增加第(2)款;
第二条增加第(3)款;
第二,增加(4);
//现在,GUI集合应该具有来自FirstCollection的以下项目2,4
//第二个系列有3个

因此,当一个对象被添加到第一个或第二个集合时,上面的guicollection应该实时工作,过滤应该被应用,过滤的项应该被添加到guicollection。我在某个地方读到Rx框架在这里真的很有帮助。请帮助我将上面的Psudeo代码替换为实际的Rx代码。谢谢。

我对Rx框架一无所知,但是只要集合的内容发生变化,ObservableCollections就会通知UI,因此您只需从绑定集合中添加/删除项即可更新UI

可以使用以下脚本完成合并:

public ObservableCollection<object> MergeCollections(
    ObservableCollection<object> first,
    ObservableCollection<object> second)
{
    foreach(var item in second)
    {
        if (!(first.Contains(item)))
            first.Add(item);
    }

    return first;
}
公共可观测集合合并集合(
首先是可观察到的收集,
可观测收集(秒)
{
foreach(第二个变量项)
{
如果(!(第一个.包含(项)))
第一,增加(项目);
}
先返回;
}

以下是我为您提供的解决方案:

Func<ObservableCollection<int>,
    Func<int, bool>,
    IObservable<int>> getAddsWhere =
        (oc, pred) =>
            from ep in Observable
                .FromEventPattern<NotifyCollectionChangedEventHandler,
                    NotifyCollectionChangedEventArgs>(
                        h => oc.CollectionChanged += h,
                        h => oc.CollectionChanged -= h)
            where ep.EventArgs.Action == NotifyCollectionChangedAction.Add
            from i in ep.EventArgs.NewItems.OfType<int>()
            where pred(i)
            select i;

var firsts = getAddsWhere(First, i => i % 2 == 0);
var seconds = getAddsWhere(Second, i => i % 3 == 0);

var boths = firsts.Merge(seconds);

boths.Subscribe(i => guicollection.Add(i));
很整洁,是吗

ObservableCollectionOperation
的定义如下:

public class ObservableCollectionOperation<T>
{
    public readonly T Value;
    public readonly Operation Operation;

    public static ObservableCollectionOperation<T> Add(T value)
    {
        return new ObservableCollectionOperation<T>(value, Operation.Add);
    }

    public static ObservableCollectionOperation<T> Remove(T value)
    {
        return new ObservableCollectionOperation<T>(value, Operation.Remove);
    }

    public ObservableCollectionOperation(T value, Operation operation)
    {
        this.Value = value;
        this.Operation = operation;
    }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode()
            * (this.Operation == Operation.Add ? 1 : -1);
    }

    public override bool Equals(object obj)
    {
        if (obj is ObservableCollectionOperation<T>)
        {
            var other = obj as ObservableCollectionOperation<T>;
            return this.Value.Equals(other.Value)
                    && this.Operation.Equals(other.Operation);
        }
        return false;
    }
}
现在是扩展方法

public static IObservable<ObservableCollectionOperation<T>>
    ToOperations<T>(this ObservableCollection<T> @this)
{
    return Observable.Create<ObservableCollectionOperation<T>>(o =>
    {
        var local = new List<T>(@this);

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getAdds = ea =>
                {
                    var xs = new T[] { };
                    if (
                        ea.Action == NotifyCollectionChangedAction.Add
                        || ea.Action == NotifyCollectionChangedAction.Replace)
                    {
                        xs = ea.NewItems.Cast<T>().ToArray();
                        local.AddRange(xs);
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Add(x))
                        .ToArray();
                };

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getRemoves = ea =>
                {
                    var xs = new T[] { };
                    if (
                        ea.Action == NotifyCollectionChangedAction.Remove
                        || ea.Action == NotifyCollectionChangedAction.Replace)
                    {
                        xs = ea.OldItems.Cast<T>().ToArray();
                        Array.ForEach(xs, x => local.Remove(x));
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Remove(x))
                        .ToArray();
                };

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getClears = ea =>
                {
                    var xs = new T[] { };
                    if (ea.Action == NotifyCollectionChangedAction.Reset)
                    {
                        xs = local.ToArray();
                        local.Clear();
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Remove(x))
                        .ToArray();
                };

        var changes =
            from ep in Observable
                .FromEventPattern<NotifyCollectionChangedEventHandler,
                    NotifyCollectionChangedEventArgs>(
                        h => @this.CollectionChanged += h,
                        h => @this.CollectionChanged -= h)
            let adds = getAdds(ep.EventArgs)
            let removes = getRemoves(ep.EventArgs)
            let clears = getClears(ep.EventArgs)
            from x in clears.Concat(removes).Concat(adds).ToObservable()
            select x;

        return changes.Subscribe(o);
    });
}
publicstaticiobservable
ToOperations(此ObservableCollection@this)
{
返回可观察的。创建(o=>
{
var local=新列表(@this);
Func
getAdds=ea=>
{
var xs=新的T[]{};
如果(
ea.Action==NotifyCollectionChangedAction.Add
||ea.Action==NotifyCollectionChangedAction.Replace)
{
xs=ea.NewItems.Cast().ToArray();
local.AddRange(xs);
}
返回xs
.选择(x=>
ObservableCollectionOperation.Add(x))
.ToArray();
};
Func
getRemoves=ea=>
{
var xs=新的T[]{};
如果(
ea.Action==NotifyCollectionChangedAction.Remove
||ea.Action==NotifyCollectionChangedAction.Replace)
{
xs=ea.OldItems.Cast().ToArray();
ForEach(xs,x=>local.Remove(x));
}
返回xs
.选择(x=>
ObservableCollectionOperation.Remove(x))
.ToArray();
};
Func
getClears=ea=>
{
var xs=新的T[]{};
if(ea.Action==NotifyCollectionChangedAction.Reset)
{
xs=local.ToArray();
local.Clear();
}
返回xs
.选择(x=>
ObservableCollectionOperation.Remove(x))
.ToArray();
};
var变化=
从可观测的ep
.FromEventPattern(
h=>@this.CollectionChanged+=h,
h=>@this.CollectionChanged-=h)
let adds=getAdds(ep.EventArgs)
let removes=getRemoves(ep.EventArgs)
let clears=getClears(ep.EventArgs)
从x开始清除.Concat(删除).Concat(添加).ToObservable()
选择x;
返回更改。订阅(o);
});
}
我添加了一个重载扩展方法来帮助过滤:

public static IObservable<ObservableCollectionOperation<T>>
    ToOperations<T>(
        this ObservableCollection<T> @this,
        Func<T, bool> filter)
{
    return @this.ToOperations().Where(op => filter(op.Value));
}
publicstaticiobservable
ToOperations(
这个可观察的集合@this,
Func(滤波器)
{
返回@this.ToOperations().Where(op=>filter(op.Value));
}
最后,我创建了一个helper方法,允许将可观察的操作播放到“observer”
observetecollection

公共静态IDisposable
订阅(
这是可以观察到的@this,
可观测(收集观察员)
{
return@this.Subscribe(op=>
{
开关(操作)
{
案例操作。添加:
观察者添加(op.Value);
打破
案例操作。删除:
移除观察者(op.Value);
打破
}
});
}

现在,是的,它确实处理删除操作,并且对您提供的示例操作有效。:-)

如果您需要不止一个
项目资源,可以使用
CompositeCollection
,谢谢。CompositeCollection是否也支持Where并具有实时更新。它确实支持,但Where
不是动态的。只要您在
可观测集合
上调用
Where
(例如,在
第一次
上),结果就不再是
可观测集合
,因此它不再提供更新。您只需要在结果集合中反映添加还是删除?添加和删除都需要。我发现ReactiveUI会很有用,但不太清楚如何使用它。谢谢。但我正在从Rx框架的角度寻找一些东西。这也能解决问题吗。@like.no.ot
public static IObservable<ObservableCollectionOperation<T>>
    ToOperations<T>(this ObservableCollection<T> @this)
{
    return Observable.Create<ObservableCollectionOperation<T>>(o =>
    {
        var local = new List<T>(@this);

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getAdds = ea =>
                {
                    var xs = new T[] { };
                    if (
                        ea.Action == NotifyCollectionChangedAction.Add
                        || ea.Action == NotifyCollectionChangedAction.Replace)
                    {
                        xs = ea.NewItems.Cast<T>().ToArray();
                        local.AddRange(xs);
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Add(x))
                        .ToArray();
                };

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getRemoves = ea =>
                {
                    var xs = new T[] { };
                    if (
                        ea.Action == NotifyCollectionChangedAction.Remove
                        || ea.Action == NotifyCollectionChangedAction.Replace)
                    {
                        xs = ea.OldItems.Cast<T>().ToArray();
                        Array.ForEach(xs, x => local.Remove(x));
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Remove(x))
                        .ToArray();
                };

        Func<NotifyCollectionChangedEventArgs,
            ObservableCollectionOperation<T>[]>
                getClears = ea =>
                {
                    var xs = new T[] { };
                    if (ea.Action == NotifyCollectionChangedAction.Reset)
                    {
                        xs = local.ToArray();
                        local.Clear();
                    }
                    return xs
                        .Select(x =>
                            ObservableCollectionOperation<T>.Remove(x))
                        .ToArray();
                };

        var changes =
            from ep in Observable
                .FromEventPattern<NotifyCollectionChangedEventHandler,
                    NotifyCollectionChangedEventArgs>(
                        h => @this.CollectionChanged += h,
                        h => @this.CollectionChanged -= h)
            let adds = getAdds(ep.EventArgs)
            let removes = getRemoves(ep.EventArgs)
            let clears = getClears(ep.EventArgs)
            from x in clears.Concat(removes).Concat(adds).ToObservable()
            select x;

        return changes.Subscribe(o);
    });
}
public static IObservable<ObservableCollectionOperation<T>>
    ToOperations<T>(
        this ObservableCollection<T> @this,
        Func<T, bool> filter)
{
    return @this.ToOperations().Where(op => filter(op.Value));
}
public static IDisposable
    Subscribe<T>(
        this IObservable<ObservableCollectionOperation<T>> @this,
        ObservableCollection<T> observer)
{
    return @this.Subscribe(op =>
    {
        switch (op.Operation)
        {
            case Operation.Add :
                observer.Add(op.Value);
                break;
            case Operation.Remove :
                observer.Remove(op.Value);
                break;
        }
    });
}