gpt4 book ai didi

wpf - 使用 Rx 合并两个 observable 集合并绑定(bind)到 Listbox

转载 作者:行者123 更新时间:2023-12-04 06:16:27 24 4
gpt4 key购买 nike

我需要将 2 个 ObservableCollection 合并为一个并将其绑定(bind)到网格,并且需要实时更新才能流向网格。例如

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

因此,当将对象添加到第一个或第二个集合时,上述 guicollection 应该实时工作,应该应用过滤并将过滤的项目添加到 guicollection。我在某处读到 Rx 框架可以在这里真正提供帮助。请帮我用实际的 Rx 代码替换上面的 Psudeo 代码。谢谢。

最佳答案

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

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));

我对其进行了测试,它按您的要求工作 - 2、3 和 4 最终出现在 guicollection 中.

编辑:更改为显示如何处理所有 NotifyCollectionChangedAction枚举值。
NotifyCollectionChangedAction枚举有五个值:
  • Add
  • Move
  • Remove
  • Replace
  • Reset
  • Move 无事可做- 这只是内部操作。
    NewItems收藏 NotifyCollectionChangedEventArgs包含 Add 的值& Replace .
    OldItems收藏 NotifyCollectionChangedEventArgs包含 Remove 的值& Replace .

    棘手的操作是 Reset - 在 Clear() 时发生在集合上调用 - 因为它不会告诉您哪些项目已清除,然后在引发事件时项目已被清除。

    所以唯一的解决方案是创建一个返回 IObservable<ObservableCollectionOperation<T>> 的扩展方法。并在内部跟踪更改,以便在 Clear 时发出一系列删除。叫做。

    在我在这里转储大量代码之前,我将向您展示调用代码的样子。这非常简单直接。
    var FirstOps = First.ToOperations(i => i % 2 == 0);
    var SecondOps = Second.ToOperations(i => i % 3 == 0);

    var BothOps = FirstOps.Merge(SecondOps);

    var subscription = BothOps.Subscribe(guicollection);

    很整洁吧?

    类(class) ObservableCollectionOperation<T>定义如下:
    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;
    }
    }
    Operation需要枚举来区分添加和删除项目,不出所料,它看起来像这样:
    public enum Operation
    {
    Add,
    Remove,
    }

    现在为扩展方法。
    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));
    }

    最后我创建了一个辅助方法来允许将可观察的操作播放到“观察者” ObservableCollection<T> :
    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;
    }
    });
    }

    现在,是的,这确实处理删除,它适用于您提供的示例操作。 :-)

    关于wpf - 使用 Rx 合并两个 observable 集合并绑定(bind)到 Listbox,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7178396/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com