我了解IObservable<T>
和IObserver<T>
是观察者模式的实现,可以在类似于.Net事件的情况下使用。
我想知道它们与INotifyPropertyChanged
是否有任何关系?
我目前在WinForms和WPF应用程序中使用INotifyPropertyChanged
进行数据绑定,并想知道是否能够在UI数据绑定场景中使用IObservable?
干杯
AWC
我了解IObservable<T>
和IObserver<T>
是观察者模式的实现,可以在类似于.Net事件的情况下使用。
我想知道它们与INotifyPropertyChanged
是否有任何关系?
我目前在WinForms和WPF应用程序中使用INotifyPropertyChanged
进行数据绑定,并想知道是否能够在UI数据绑定场景中使用IObservable?
干杯
AWC
IObservable
,否则它不能帮助保持UI随模型更改而更新。使用INotifyPropertyChanged
的原因是,WinForms和WPF中的绑定代码会寻找此接口,并在其实现时使用其事件来保持UI最新。并且:
http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html
这就像是苹果和橙子一样。
INotifyPropertyChanged只是提供了一个通用的事件绑定,让数据绑定等知道何时更新它们的绑定值。
IObservable/IObserver更像是“使用事件序列查询”,但即使如此,这也是一个不太准确的描述。
嗯...好吧,你知道怎么把东西放在叫做集合的“袋子”里,然后查询该集合(手动或使用LINQ语句)以提取值,对吧?有点像那样,但不同的是,你得到的是“推送”给你的事件,而不是从“袋子”中“拉”出数据。
无耻地插入一条可能有帮助或进一步混淆的广告: http://blog.lab49.com/archives/3252
IObservable<T>
的最直接方式是创建一个传统的视图模型对象,如下所示,并手动订阅它到可观察对象。应该使用.ObserveOn(SynchronizationContext.Current)
执行订阅以在UI线程中分派所有通知。反过来,同步上下文应该在那个时刻存在(SynchronizationContext.Current
在new Application().Run(mainWindow)
之前为null)。请参见以下示例:public class ViewModel : INotifyPropertyChanged
{
private int _property1;
public int Property1
{
get => _property1;
set
{
_property1 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property1)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
视图:
<Window x:Class="ConsoleApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBox Text="{Binding Property1}" />
</Window>
调用方方法:
[STAThread]
static void Main()
{
var model = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1)).Take(10);
var viewModel = new ViewModel();
var mainWindow = new MainWindow
{
DataContext = viewModel
};
IDisposable subscription = null;
mainWindow.Loaded += (sender, e) =>
subscription = model
.ObserveOn(SynchronizationContext.Current) // Dispatch all the events in the UI thread
.Subscribe(item => viewModel.Property1 = item);
new Application().Run(mainWindow);
subscription?.Dispose();
}
另一个选项是使用 ReactiveUI.WPF,甚至更加简洁的 ReactiveUI.Fody 生成视图模型中的自动属性。
视图模型:
public class ViewModel : ReactiveObject, IDisposable
{
private readonly IDisposable subscription;
public ViewModel(IObservable<long> source)
{
subscription = source
.ObserveOnDispatcher()
.ToPropertyEx(this, x => x.Property1);
}
// To be weaved by Fody
public extern long Property1 { [ObservableAsProperty]get; }
// Unsubscribe from the source observable
public void Dispose() => subscription.Dispose();
}
这里的ObserveOnDispatcher()
调用即使调度程序尚未启动并且SynchronizationContext.Current
为空也可以工作。
调用者方法:
[STAThread]
static void Main()
{
new Application().Run(
new MainWindow
{
DataContext = new ViewModel(
Observable.Timer(
TimeSpan.Zero,
TimeSpan.FromSeconds(1))
.Take(20))
});
}
解决方案文件附近的FodyWeavers.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<ReactiveUI />
</Weavers>
我同意micahtan和NathanAW的回答。我想简要总结并补充一下。严格来说,IObservable和INotifyPropertyChanged之间没有直接联系。Rx是从事件特定的抽象出发:它是处理任何类型事件的框架。RX以相同的方式处理所有类型的事件,所有的细节都在用户代码中。如果你想在WPF(Xamarin、Blazor)中确切地从INotifyPropertyChanged和INotifyCollectionChanged中获益,请看看我的ObservableComputations库。这个库是Bindable Linq、Continuous Linq、Optics库的生产就绪模拟版,NathanAW建议使用这些库。这些库可以单独使用,也可以与Rx协作。在这种情况下,Rx和INotifyPropertyChanged之间存在联系,但同样的联系也存在于Rx和任何其他事件之间。