我了解IObservable<T>
&IObserver<T>
是观察者模式的实现,可以在与 .Net 事件类似的情况下使用。
我想知道是否有任何关系INotifyPropertyChanged
?
我目前INotifyPropertyChanged
用于 winforms 和 WPF 应用程序中的数据绑定,想知道是否可以在 UI 数据绑定场景中使用 IObservable?
干杯
AWC
我了解IObservable<T>
&IObserver<T>
是观察者模式的实现,可以在与 .Net 事件类似的情况下使用。
我想知道是否有任何关系INotifyPropertyChanged
?
我目前INotifyPropertyChanged
用于 winforms 和 WPF 应用程序中的数据绑定,想知道是否可以在 UI 数据绑定场景中使用 IObservable?
干杯
AWC
据我所知,没有任何关系。Observers/.NET 事件是实现 Observer/Notification 样式行为的两种方式。
微软的答案是建立在 .NET 事件模式之上,而不是弃用它,而支持手动注册的 Observer 对象。
我对事件最大的不满之一是无法按需清除委托链,这会导致很多托管内存泄漏情况。为此,微软引入了弱事件的概念,即解决 Observables/Observers 时间线不匹配的问题。
您可以在此处阅读有关 WeakEvent 模式的更多信息。
Josh Smith 在这里发布了 INotifyPropertyChanged 的 WeakEventManager 的实现。这提供了一种更安全(从内存的角度来看)连接更改属性的对象及其观察者的方法。
除非 WinForms 和 WPF 绑定也支持IObservable
,否则使用模型中的更改来保持 UI 更新是没有帮助的。您可以使用的原因INotifyPropertyChanged
是因为 WinForms 和 WPF 中的绑定代码会查找此接口,并在实现时使用其事件来使 UI 保持最新。
首先,我对 Rx 有点陌生,所以请相应地发表我的评论。
也就是说,我认为 INotifyPropertyChanged 和 Rx 的 IObservable 之间有很大的合作机会。我认为在这一点上 UI 是围绕 INPC 构建的相对明显。但是,INPC 也是检测更改和管理领域模型或视图模型在对象和属性之间具有相互依赖关系的场景的主要方式。正是这些相互依赖似乎是 Rx 的良好候选者。
直接使用 INPC 有点棘手,也有点痛苦。很多魔术字符串要处理。在对象树中观察多个级别的对象上的事件也有点痛苦。
但是,如果我可以“响应式”地对这些交互进行建模,那么我的视图模型和域模型就会开始变得更加优雅。这在Bindable Linq、Continuous Linq、Obtics等项目的优雅中很明显。这些库使创建“实时值”或“实时集合”变得简单,自动更新(我敢说是“响应式”)更改。Continuous Linq 甚至有一个“反应式对象”框架来进行反应式编程,尽管没有 Rx。
在我看来,如果我们可以使用 Rx 来保持模型和视图模型的一致性,就会产生协同效应。然后我们可以通过根据需要继续提高 PropertyChanged 来使模型/视图模型的“可绑定表面”尊重 INPC。我见过几个优雅的扩展方法,它们会从 INotifyPropertyChanged 创建一个 observable。似乎另一半可能是创建一些从 Rx 转换回 INPC 的基础设施。
如果您指的是 Rx 扩展定义的 IObserver/IObservable:
和:
http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html
然后它就像苹果和橘子。
INotifyPropertyChanged 只是为数据绑定/等提供了一个通用事件连接,让控件知道何时更新其绑定值。
IObservable/IObserver 更像是“使用事件序列查询”,但即使这样描述也很糟糕。
嗯...好的,所以您知道如何将东西放入这个称为集合的“包”中,然后查询该集合(手动或使用 LINQ 语句)以提取值,对吧?有点像那样,但不是从“袋子”中“拉”出数据,而是将事件“推送”给您。
可能有助于或进一步混淆的无耻插件:http: //blog.lab49.com/archives/3252
通常,使用 MVVM 呈现最直接的方法IObservable<T>
是制作一个像下面这样的传统视图模型对象,然后手动将其订阅到 observable。应该使用订阅.ObserveOn(SynchronizationContext.Current)
来调度 UI 线程中的所有通知。反过来,同步上下文应该在那个时刻存在(SynchronizationContext.Current
之前为空new Application().Run(mainWindow)
)。请参阅下面的示例:
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>
I agree with micahtan's and NathanAW's answers. I want just summarize and add. In the strict sense, there is no direct connection beetwen IObservable and INotifyPropertyChanged. Rx is abstracted from event specific: it is framework for processing any types of events. RX handles all types of events in the same way and all specifics are only in user code. If you want to get benefit exactly from INotifyPropertyChanged and INotifyCollectionChanged in your WPF (Xamarin, Blazor) expearence take a look on my ObservableComputations library. This library is a production-ready analogue of the Bindable Linq, Continuous Linq, Optics libraries that NathanAW advised.These libraries can be used themselves or cooperated with Rx. In that sence there is connection beetwen Rx and INotifyPropertyChanged, but again, the same connection exists beetwen Rx and any other event.