Observable.FromEventPattern 关于 ObservableCollection

Observable.FromEventPattern on ObservableCollection

我有一个 ClassWrapper class 和一个 BaseClassWrapper class。 BaseClassWrapper 有一个 ClassDTO 类型的对象,里面有一个 ObservableCollection,这就是我想要的 "observe"。当我创建一个 "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>();
}

我尝试了代码并每 100 毫秒添加一个新项目并且...至少可以说是困惑,直到我不小心将鼠标悬停在 Throttle 上并看到:

Ignores elements from an observable sequence which are followed by another element within a specified relative time duration.

我怀疑您和我一样,期望 Throttle() 到 return window 中的最后一项。尽管它在 ReactiveX.io 中的描述是

only emit an item from an Observable if a particular timespan has passed without it emitting another item

文档备注说:

For streams that never have gaps larger than or equal to dueTime between elements, the resulting stream won't produce any elements.

事实上,我以前就是这样使用的,但不知何故我每次都被这个名字绊倒,直到我记得实际操作是 debouncing,而不是 throttling .

当我减慢计时器触发速度时,例如每 300 毫秒我开始得到结果。

return 是 window 中最后一个事件的运算符是 Sample,而不是 Throttle。如果那是你想要的,你应该使用

.Sample( TimeSpan.FromMilliseconds(300))

而不是 Throttle

如果您只想更新 UI,请使用 Throttle 通知停止 250 毫秒后

更新

为了测试这种行为,我创建了一个控制台应用程序。我在问题的代码中添加了几个修复程序以允许它编译:

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