这是一个简短的问题。我有一个ObservableCollection<IItem>
,其中IItem
有一个名为Id的属性。在整个应用程序的生命周期中,项目将被添加,删除,然后再次重新添加到此集合中。
我需要的是跟踪此集合中是否存在具有特定ID的项目。当存在所有必需的依赖项时,我需要进行一些初始化,如果至少删除了一个必需项,那么我需要进行清理。如果该项再次重新添加,那么我需要再次进行初始化。
有什么建议RX运营商用来构建这种查询吗?
答案 0 :(得分:1)
跟踪收集的状态可能有点单调乏味。除非您的集合非常大,否则您可以检查每次更改的集合,以确定是否满足初始化条件。然后,您可以使用DistinctUntilChanged
来获取在需要执行初始化和清理时将触发的可观察对象
以下是一个例子:
var collection = new ObservableCollection<Int32>();
var observable = Observable
.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
handler => collection.CollectionChanged += handler,
handler => collection.CollectionChanged -= handler
);
然后,您需要一个判断是否需要初始化的谓词(集合“已准备就绪”)。如果你的集合很大,这个谓词可能会变得昂贵,因为每次对集合的更改都会调用它,但我的假设是这不是问题。
Boolean IsReady(IEnumerable<Int32> items, IReadOnlyList<Int32> itemsRequiredToBeReady) {
return items.Intersect(itemsRequiredToBeReady).Count() == itemsRequiredToBeReady.Count;
}
然后,当DistinctUntilChanged
谓词从true更改为false时,您可以使用IsReady
来收到通知,反之亦然:
var isReadyObservable = observable
.Select(ep => IsReady((ObservableCollection<Int32>) ep.Sender, ItemsRequiredToBeReady))
.DistinctUntilChanged();
要初始化和清理,您需要两个订阅:
isReadyObservable.Where(isReady => isReady).Subscribe(_ => Initialize());
isReadyObservable.Where(isReady => !isReady).Subscribe(_ => Cleanup());
答案 1 :(得分:0)
ObservableCollection不能像it turns out那样被观察到,所以首先你必须考虑在这种情况下你将采用什么策略。如果只是添加和删除项目,则此代码应该足够。
internal class Program
{
private static ObservableCollection<IItem> oc = new ObservableCollection<IItem>();
private static readonly long[] crossCheck = {1,2,3};
private static void Main(string[] args)
{
oc.CollectionChanged += oc_CollectionChanged;
oc.Add(new IItem {Id=1,Amount = 100});
oc.Add(new IItem {Id=2,Amount = 200});
oc.Add(new IItem {Id=3,Amount = 300});
oc.RemoveAt(1);
}
private static void oc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine("{0} {1}", e.Action, oc.Sum(s1 => s1.Amount));
if (crossCheck.SequenceEqual(oc.Select(s1 => s1.Id).Intersect(crossCheck)))
Console.WriteLine("I have all elements I wanted!");
if (e.OldItems != null && e.Action.Equals(NotifyCollectionChangedAction.Remove) &&
e.OldItems.Cast<IItem>().Any(a1 => a1.Id.Equals(2))) Console.WriteLine("I've lost item two");
}
}
internal class IItem
{
public long Id { get; set; }
public int Amount { get; set; }
}
产地:
Add 100
Add 300
Add 600
I have all elements I wanted!
Remove 400
I've lost item two
Press any key to continue . . .
当然,在您的事件处理程序中,您可以根据需要处理其他条件,例如,您可能只需要触发一些与数据相关的事件,等等。