为什么没有人使用INotifyPropertyChanging?

我知道MVVM大量使用INotifyPropertyChanged,但我从未见过使用过任何INotifyPropertyChanging。 有什么理由吗?

如果我确实想要使用它,那么将它集成到我的MVVM框架中的好方法是什么? 我知道你不应该在ViewModel上使用MessageBox ,因为那时你无法对它进行unit testing。 那么如何提出警报,然后继续使用PropertyChange(如果适用)?

关于INotifyPropertyChanging要记住的一点是你无法阻止变化的发生。 这仅允许您记录发生的更改。

我在我的框架中使用它进行更改跟踪,但它不是停止更改的适当方法。

您可以使用自定义接口/事件对扩展ViewModelBase

 delegate void AcceptPendingChangeHandler( object sender, AcceptPendingChangeEventArgs e); interface IAcceptPendingChange { AcceptPendingChangeHandler PendingChange; } class AcceptPendingChangeEventArgs : EventArgs { public string PropertyName { get; private set; } public object NewValue { get; private set; } public bool CancelPendingChange { get; set; } // flesh this puppy out } class ViewModelBase : IAcceptPendingChange, ... { protected virtual bool RaiseAcceptPendingChange( string propertyName, object newValue) { var e = new AcceptPendingChangeEventArgs(propertyName, newValue) var handler = this.PendingChange; if (null != handler) { handler(this, e); } return !e.CancelPendingChange; } } 

此时,您需要按惯例将其添加到视图模型中:

 class SomeViewModel : ViewModelBase { public string Foo { get { return this.foo; } set { if (this.RaiseAcceptPendingChange("Foo", value)) { this.RaiseNotifyPropertyChanging("Foo"); this.foo = value; this.RaiseNotifyPropretyChanged("Foo"); } } } } 

INotifyPropertyChanging是用于Linq to SQL的优化。 当一个对象实现此接口时,它使用更改事件作​​为缓存属性旧值的信号。 如果对象没有实现此接口,那么它将始终缓存属性值,从而增加内存使用量。 有关更多详细信息,请参阅INotifyPropertyChanging接口如何帮助限制内存消耗 。

要回答第二个问题,您可以始终使用dependency injection模式使您的VM依赖于接口(INotifier?)并传递弹出MessageBoxes的具体实现。 这使单元可测试性保持不变。

编辑:对于SO来说,第一个问题可能过于主观。 界面的意图很明确,但何时使用它将是非常具体的用例。 依赖属性会产生类似的效果,它可以在应用之前检查新值是否有用,但如果您使用简单的属性,那么您可以更简单地将此检查放入您的setter中。 如果一个不同的组件需要检查有效性,那么如果该组件本身进行了更改(在validation新值之后)或者被显式调用以通过进行更改的组件validation更改,则通常会更简单。

在属性更改之前调用INotifyPropertyChanging。 重要的原因? 这样外部事件处理程序就可以抛出exception并阻止更改。 你为什么要那样做? 有一天,它可能是你唯一的解决方法,以防止其他人的代码库中的错误,所以不要那么快删除逃生舱。

例如,如果您想知道何时更改任何变量,则需要使用INotifyPropertyChanged,因为您可以使用PropertyChangedEventHandler。 通过这种方式,您可以在运行程序时重新加载gui,如果任何依赖属性绑定在任何gui元素上。

对于最后一个问题,我认为您可以使用已定义的消息编写日志文件,如果要向用户显示任何警报,则可以使用错误摘要或工具提示等控件。 但是如果你只需要这个用于测试,你可以使用try和catch块来保持警报。