這裏是我的解決方案爲您提供:
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,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);
非常整齊,是吧?
類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;
}
});
}
現在,是的,這是處理刪除,它適用於您提供的示例操作。 :-)
如果你需要多個'ItemsSource',你可以使用'CompositeCollection' –
謝謝。 CompositeCollection是否也支持Where和實時更新。 –
是的,它確實沒有 –