现在的位置: 首页 > 综合 > 正文

MVVM Light V3:ViewModelBase和其属性值的改变处理

2013年05月16日 ⁄ 综合 ⁄ 共 3112字 ⁄ 字号 评论关闭

 

 

 

 

 

返回目录

ICleanup和IDisposable

MVVM Light中的ViewModelBase同时执行ICleanup接口和IDisposable接口。前者是来自MVVM Light类库本身,后者则是.NET的产物。两者是为了完成同样类型的事件,而且IDisposable的Dispose是不推荐使用的(被标记有Obsolete特性),当然用户仍然可以通过重写Dispose方法。

 

至于为什么推荐用ICleanup那还执行IDisposable?Laurent Bugnion先生曾经在StackOverflow中解释过这个问题,地址:

http://stackoverflow.com/questions/2963151/cleanup-vs-disposebool-in-mvvm-light

 

简单地将就是:本来最初只有IDisposable,但是.NET中IDisposable的用途通常代表着执行完后则可以被垃圾回收的,但是ViewModel中的资源清理逻辑并不一定代表着ViewModel马上要等待着GC销毁,也许仅仅是数据存储、关闭文件流等操作。因此ICleanup诞生了。

 

ViewModelBase执行ICleanup是直接定义一个public virtual的Cleanup方法。并且取消当前对象在默认Messenger注册的任何消息。如源代码:

Messenger.Default.Unregister(this);

 

Dispose方法则是.NET中Dispose方法执行的模式,public Dispose方法会调用protected Dispose方法,且disposing参数为True。

 

 

 

 

返回目录

属性改变处理:PropertyChanged和Broadcast

ViewModelBase同时执行INotifyPropertyChanged,因此定义PropertyChanged事件。同时定义RaisePropertyChanged(等于OnPropertyChanged)方法来执行事件,参数是属性名称。RaisePropertyChanged会把属性名称包装在PropertyChangedEventArgs中(在System.ComponentModel)然后执行PropertyChanged事件。这个.NET事件定义的套路,不需要多解释了。

 

ViewModelBase同时定义了另一个RaisePropertyChanged方法。该方法的参数是:

(string propertyName, T oldValue, T newValue, bool broadcast)

 

如果broadcast为false的话,那么和上一个RaisePropertyChanged的执行是一样的,如果broadcast为true,那么该属性改变事件不仅会调用普通的RaisePropertyChanged方法,同时还会调用另一个Broadcast方法来把这个属性改变的事件(或者说是消息),通过MVVM Light特有的消息模式来传播。

 

Broadcast方法首先会把信息包装在PropertyChangedMessage<T>类型中,此类型继承自PropertyChangedMessageBase,一个非泛型的执行,他们都属于MessageBase:MVVM Light中的基础消息类型。

image

 

接着Broadcast方法判断当前ViewModelBase是否已经绑定一个IMessenger,ViewModelBase的一个构造函数运行传入一个自定义的IMessenger类型。如果没有绑定的话,使用默认Messenger(通过Messenger.Default属性)。最后使用IMessenger的Send方法发送消息。

 

另外ViewModelBase定义了MessengerInstance属性(继承类可见可改写,类型IMessenger)可以修改绑定的ViewModelBase中的默认IMessenger。

 

当用户定义自己的属性成员时,可以根据需求选择哪个RaisePropertyChanged方法。同时在使用MVVM Light的mvvminpc Code Snippet时,会直接生成类似如下完整代码:

/// <summary>

/// The <see cref="MyProperty" /> property's name.

/// </summary>

public const string MyPropertyPropertyName = "MyProperty";

 

private bool _myProperty = false;

 

/// <summary>

/// Gets the MyProperty property.

/// TODO Update documentation:

/// Changes to that property's value raise the PropertyChanged event.

/// This property's value is broadcasted by the Messenger's default instance when it c

/// </summary>

public bool MyProperty

{

    get

    {

        return _myProperty;

    }

 

    set

    {

        if (_myProperty == value)

        {

            return;

        }

 

        var oldValue = _myProperty;

        _myProperty = value;

 

        // Remove one of the two calls below

        throw new NotImplementedException();

 

        // Update bindings, no broadcast

        RaisePropertyChanged(MyPropertyPropertyName);

 

        // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging

        RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);

    }

}

 

在下面,用户自己选择调用哪种方法,当然别忘了把throw new NotImplementedException();这句也删了。

 

 

更新:

更多关于Messenger可以参考另外一篇文章:

MVVM Light:消息系统的IMessenger

 

 

 

返回目录

判断成员

ViewModelBase同时提供许多判断类型的成员。

 

比如VerityPropertyName方法,首先它带有Conditional("DEBUG")特性,因此在Release模式下不会被编译进去。使用它可以判断当前ViewModel是否存在指定名称的属性。如果没有,ArgumentException异常抛出。

 

同时还有静态的IsInDesignModeStatic属性和非静态的IsInDesignMode属性来判断执行环境是否是设计模式(比如Visual Studio设计器或者Blend)。用户可以根据不同模式来执行不用的代码,比如在设计模式下考虑快速生成一些数据做演示。

抱歉!评论已关闭.