为什么没有人使用INotifyPropertyChanging?

时间:2011-11-03 13:41:09

标签: c# wpf mvvm

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

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

5 个答案:

答案 0 :(得分:12)

关于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");
             }
         }
     }
}

答案 1 :(得分:4)

INotifyPropertyChanging是用于Linq to SQL的优化。当对象实现此接口时,它使用更改事件作​​为缓存属性旧值的信号。如果对象没有实现此接口,那么它将始终缓存属性值,从而增加内存使用量。 有关详细信息,请参阅How does INotifyPropertyChanging interface helps limit memory consumption

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:-6)

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

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