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();
}
我有一个 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();
}