ObservableCollection上的Observable.FromEventPattern

时间:2019-01-17 15:40:44

标签: c# wpf xaml system.reactive

我有一个ClassWrapper类和一个BaseClassWrapper类。 BaseClassWrapper具有ClassDTO类型的对象,并且在其内部具有ObservableCollection,这就是我要“观察”的对象。当我创建“ ClassWrapper”类型的对象并将一个项目添加到集合ClassWrapper.ClassDTO.MyCollection.Add(new OtherClass())时,观察者将无法使用。

但是,如果我在ClassWrapper(不是在BaseWrapper中)内创建ClassDTO或ObservableCollection,它会完美地工作。为什么会这样?

public class ClassWrapper : BaseClassWrapper
{
    public ClassWrapper()
    {
        Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
                (x => ClassDTO.MyCollection.CollectionChanged += x, x => ClassDTO.MyCollection.CollectionChanged -= x)
            .Where(x => x.EventArgs.Action == NotifyCollectionChangedAction.Add ||
                        x.EventArgs.Action == NotifyCollectionChangedAction.Replace ||
                        x.EventArgs.Action == NotifyCollectionChangedAction.Remove)
            .Throttle(TimeSpan.FromMilliseconds(250))
            .Subscribe(x =>
            {
                RaisePropertyChanged(SomeProperty);
            });
    }
}

public abstract class BaseClassWrapper : ObservableObject // MVVM Light
{
    public ClassDTO ClassDTO { get; set; } = new ClassDTO();
}

public class ClassDTO
{
    public ObservableCollection<OtherClass> MyCollection { get; set; } = new ObservableCollection<OtherClass>();
}

1 个答案:

答案 0 :(得分:2)

我尝试了代码,每100毫秒添加了一个新项目,然后……至少让我感到困惑,直到我不小心将鼠标悬停在Throttle上并看到了:

  

忽略可观察序列中的元素,然后在指定的相对持续时间内跟随另一个元素。

我怀疑像我一样,您希望Throttle()返回窗口中的最后一项。即使在ReactiveX.io中的描述是

  

仅在经过特定时间跨度时才从Observable中发射一项,而不发射另一项

文档说明说:

  

对于元素之间的间隙永远不大于或等于DueTime的流,结果流将不产生任何元素。

事实上,我过去曾经用过这种方式,但是每次我都会用这个名字来打翻,直到我记得实际的操作是反跳,而不是节制。

当我放慢计时器触发时间(例如每300毫秒)时,我就会开始获得结果。

返回窗口中最后一个事件的运算符是Sample,而不是Throttle。如果那是您想要的,则应使用

.Sample( TimeSpan.FromMilliseconds(300))

代替Throttle

如果您要仅在 通知停止发出250毫秒后更新用户界面,请使用Throttle

更新

为了测试此行为,我创建了一个控制台应用程序。我为问题的代码添加了一些修复程序,以使其可以编译:

public class ClassWrapper : BaseClassWrapper
{
    public string SomeProperty { get; set; }
    public ClassWrapper()
    {
        Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
                (x => ClassDTO.MyCollection.CollectionChanged += x, x => ClassDTO.MyCollection.CollectionChanged -= x)
            .Where(x => x.EventArgs.Action == NotifyCollectionChangedAction.Add ||
                        x.EventArgs.Action == NotifyCollectionChangedAction.Replace ||
                        x.EventArgs.Action == NotifyCollectionChangedAction.Remove)
            .Throttle( TimeSpan.FromMilliseconds(250))
            .Subscribe(x =>
            {
                RaisePropertyChanged( ()=> SomeProperty);
            });
    }
}

应用程序的Main方法每100毫秒添加一个项目。添加最后一项后250毫秒,将引发单个通知事件并显示一条消息:

static async Task Main(string[] args)
{
    Console.WriteLine("Started");
    var c = new ClassWrapper();
    c.PropertyChanged += (sender, e) =>
    {
        Console.WriteLine($"Collection has {c.ClassDTO.MyCollection.Count} items");
    };

    for (int i = 0; i < 100; i++)
    {
        c.ClassDTO.MyCollection.Add(new OtherClass());
        await Task.Delay(100);

    }

    Console.ReadKey();
}