我需要将2个ObservableCollection合并为一个并将其绑定到网格,并需要实时更新才能流向网格。 .e.g。
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代码。感谢。
答案 0 :(得分:3)
以下是我的解决方案:
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和&amp; 4结束于guicollection
。
编辑:已更改以显示如何处理所有NotifyCollectionChangedAction
枚举值。
NotifyCollectionChangedAction
枚举有五个值:
Add
Move
Remove
Replace
Reset
Move
无关 - 它只是一个内部操作。
NewItems
上的NotifyCollectionChangedEventArgs
集合包含Add
&amp;的值{} Replace
。
OldItems
上的NotifyCollectionChangedEventArgs
集合包含Remove
&amp;的值{} 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);
非常整洁,是吗?
类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;
}
});
}
现在,是的,这会处理删除,它可以处理您提供的示例操作。 : - )
答案 1 :(得分:0)
我对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;
}