在我正在使用的WPF应用程序中,我遇到了以下代码片段;
public int SomeInteger
{
get { return _someInteger; }
set
{
_someInteger= value;
OnPropertyChanged("SomeInteger");
SomeIntegerChanged();
}
}
如您所见,在属性设置器中调用了一个方法。这种方法是正确的还是在MVVM模式WPF中有更好的方法?
上面的代码段是一个示例,实际上,当属性更改时,属性设置器可能会加载DataTable
,这可能很耗时。我尝试使用async
和await
使应用程序异步,但是由于async
和await
没有异步属性概念,因此上述情况会导致问题。
我还找到了一种将事件绑定到INotifyPropertyChanged
的方法,并通过检查哪个属性触发了该事件并调用了该方法。但是正在寻找其他选择。
答案 0 :(得分:5)
这种方法是正确的还是在MVVM模式WPF中有更好的方法吗?
不幸的是,这是跨所有C#的通用和公认的MVVM模式。我说“不幸”是因为这种模式确实遇到了问题。它基于事件-本身就存在问题-并且还会导致立即更新,这在许多情况下是不希望的。
例如,有时希望具有两个相互依赖的属性-当用户更改一个属性时,另一个属性相对于它改变-这会引起问题,因为无法将“用户更改”与“代码更改”。
再举一个例子,有时您可能会得到一整套依赖属性的树,并且所有更改都需要花费一些时间才能传播并停止相互干扰。
更现代的MVVM方法(如原子更新的单一真理源和单向数据流(由Redux推广))避免了上述问题。有一个C#Redux实现;我不知道使用起来有多容易。在我自己的CalculatedProperties library中,我建立了自己的“无效队列”来解决此问题,defers all PropertyChanged
updates直到计算出整个系统的新稳态之后。
我试图使用async和await使应用程序异步,但是由于async和await没有异步属性概念,因此上述情况会导致问题。
是的。特别是,您不能“异步获取”属性。这在MVVM世界中是有意义的。当WPF更新屏幕时,它要求您的VM提供数据值,那么您的VM无法说“保持,我将在一分钟内得到它”。 WPF需要知道该值 now ,以便它可以更新屏幕 now 。
连接一个异步事件处理程序是在值更改时启动异步工作的一种方法。这种方法很好。通常,SomeIntegerChanged
的存在意味着该属性专门存在一个“已更改”事件,因此使用字符串比较插入PropertyChanged
可能是更困难的方法
有关MVVM的异步属性的更多信息,请参见我的article on the subject。
答案 1 :(得分:2)
在这种情况下,可以在Setter中调用方法。在WPF中将INotifyPropertyChanged
用于属性更改通知是正确的方法,将调用添加到Setter是实现它的默认方法。
对SomeIntegerChanged();
的调用在某种程度上取决于该方法的功能(如果已经实现了INotifyPropertyChanged
,甚至需要调用该方法)。
将属性用作消费者应该具有尽可能小的副作用,并且通常应该是简单的操作。 MSDN上有关于该主题的不错的指南。
您还应避免使用属性名称字符串作为参数,在这种情况下,对OnPropertyChanged
的调用应如下所示:OnPropertyChanged(nameof(SomeInteger));
答案 2 :(得分:2)
属性设置器不应该启动长期运行的操作。它应该简单地设置后备字段的值,并可能调用几乎立即返回的快速同步方法。有关更多信息,请参阅@Stephen Cleary的blog post。
如果每次设置SomeInteger
时都需要调用异步方法,则可以例如为async
事件挂接一个PropertyChanged
事件处理程序,例如:
this.PropertyChanged += async (s, e) =>
{
if (e.PropertyName == nameof(SomeInteger))
{
await SomeAsyncMethod();
}
};
答案 3 :(得分:0)
我会提防过早的优化。
不要使您的解决方案复杂化。
如果更改是立即进行的,那么将您喜欢的内容放入设置器中就没有问题。
依赖的属性更改只是偶尔的要求,但通常也没什么大碍。
如果您需要漫长的过程才能开始,那么听起来好像应该是离散的。您应该在单独的线程上启动该处理,或者解耦该处理。您可能只是开火而忘记线程(不是很优雅)。
您可以使用服务调用,消息队列(例如msmq或RabbitMQ或pub sub)来分离处理。有很多pub子方法-一个简单的实现是mvvmlight的Messenger或Prism的eventaggregator。更复杂的将是NServiceBus甚至Windows Workflow。如果涉及事件,那么弱事件是可取的。