目录
1介绍MVVMLight
试用范围: Windows Presentation Foundation, Silverlight and for Windows Phone 7
作者的介绍
- The GalaSoft.MvvmLight library with helper classes:
- A ViewModelBase class to be used as the base class for ViewModels.
- A Messenger class (and diverse message types) to be used to communicate within the application. Recipients only receive the message types that they register for. Additionally, a target type can be specified, in which case the message will only be transmitted if the recipient's type matches the target parameter.
Messages can be anything from simple values to complex objects. You can also use specialized message types, or create your own types deriving from them.
More information about the Messenger class.- MessageBase: A simple message class, carrying optional information about the message's sender.
- GenericMessage<T>: A simple message with a Content property of type T.
- NotificationMessage: Used to send a notification (as a string) to a recipient. For example, save your notifications as constant in a Notifications class, and then send Notifications.Save to a recipient.
- NotificationMessage<T>: Same as above, but with a generic Content property. Can be used to pass a parameter to the recipient together with the notification.
- NotificationMessageAction: Sends a notification to a recipient and allows the recipient to call the sender back.
- NotificationMessageAction<T>: Sends a notification to a recipient and allows the recipient to call the sender back with a generic parameter.
- DialogMessage: Used to request that a recipient (typically a View) displays a dialog, and passes the result back to the caller (using a callback). The recipient can choose how to display the dialog, either with a standard MessageBox, with a custom popup, etc…
- PropertyChangedMessage<T>: Used to broadcast that a property changed in the sender. Fulfills the same purpose than the PropertyChanged event, but in a less tight way.
- Command classes optimized for WPF and Silverlight and simplifying commanding in your application. Available with or without generic parameter (RelayCommand<T> and RelayCommand). For an in-depth analysis, I encourage you to read Using RelayCommands in Silverlight and WPF
- The GalaSoft.MvvmLight.Extras library with optional classes:
- EventToCommand behavior, allowing you to bind any event of any UI element to an ICommand, for example on the ViewModel, directly in XAML. This makes using Commands much easier, without writing code behind. With the newest version, you can even get the EventArgs of the fired event directly in the ViewModel to handle it.
- DispatcherHelper class, a lightweight class helping you to create multithreaded applications.
==
2代码分析方法
2.1 按照骑士的建议,先从测试代码看起。完整了解其功能。
2.2 使用类图看其结构。
3.3 顾名思义+debug看其执行。
之前我还去TOPLANGUAGE整理了一下牛牛们的想法,也一并贴出来供大家参考。排版乱抱歉。
3具体剖析
打开源码我们可以看到
进入测试代码
3.1 消息机制的剖析
ViewModelBaseTest ,我们知道他是通过以下 步骤来使用其消息机制的
void TestSimpleSendANDRevice()
{
Messenger.Reset();//把MESSAGER 单例 重置 为 空
var vm = new TestViewModel();
//注册
//1接受 string 类型的 消息
//2收到消息 时候 调用 HandleStringMessage
Messenger.Default.Register<string>(vm, vm.HandleStringMessage);
const string Content1 = "Hello world";
Messenger.Default.Send(Content1);//此时发送
Assert.AreEqual(Content1, vm.ReceivedContent);
}
public class TestViewModel : ViewModelBase
{
string ReceivedContent ;
internal void HandleStringMessage(string message)
{
ReceivedContent = message;
}
}
{
Messenger.Reset();//把MESSAGER 单例 重置 为 空
var vm = new TestViewModel();
//注册
//1接受 string 类型的 消息
//2收到消息 时候 调用 HandleStringMessage
Messenger.Default.Register<string>(vm, vm.HandleStringMessage);
const string Content1 = "Hello world";
Messenger.Default.Send(Content1);//此时发送
Assert.AreEqual(Content1, vm.ReceivedContent);
}
public class TestViewModel : ViewModelBase
{
string ReceivedContent ;
internal void HandleStringMessage(string message)
{
ReceivedContent = message;
}
}
那么他的底层又是如何实现的呢?
让我们进入看看他的Messenger和其接口
首先是其Register函数
/// <summary>
/// Registers a recipient for a type of message TMessage.
/// 为T类型的参数 注册一个接受者,
/// The action parameter will be executed when a corresponding (相应的)
/// (当接收到) 参数action 这个方法将被执行
/// message is sent. See the receiveDerivedMessagesToo parameter
/// for details on how messages deriving from TMessage (or, if TMessage is an interface,
/// messages implementing TMessage) can be received too.
/// 是否 接收 接口的 派生类的 信息
/// <para>Registering a recipient does not create a hard reference to it,
/// so if this recipient is deleted, no memory leak is caused.</para>
/// </summary>
/// <typeparam name="TMessage">The type of message that the recipient registers
/// for.</typeparam>
/// <param name="recipient">The recipient that will receive the messages.</param>
/// <param name="token">A token(标记) for a messaging channel.
/// token 是一个 栏目的标记
/// If a recipient registers
/// using a token, and a sender sends a message using the same token, then this
/// 发送和接收方使用同一个标记 token接收 才能 接收到
/// message will be delivered to the recipient. Other recipients who did not
///
/// use a token when registering (or who used a different token) will not
/// get the message.
///
/// Similarly, messages sent without any token, or with a different
/// token, will not be delivered to that recipient.</param>
///
/// <param name="receiveDerivedMessagesToo">If true, message types deriving from
/// TMessage will also be transmitted to the recipient. For example, if a SendOrderMessage
/// and an ExecuteOrderMessage derive from OrderMessage, registering for OrderMessage
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
/// and ExecuteOrderMessage to the recipient that registered.
///
/// <para>Also, if TMessage is an interface, message types implementing TMessage will also be
/// transmitted to the recipient. For example, if a SendOrderMessage
/// and an ExecuteOrderMessage implement IOrderMessage, registering for IOrderMessage
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
/// and ExecuteOrderMessage to the recipient that registered.</para>
/// </param>
/// <param name="action">The action that will be executed when a message
/// of type TMessage is sent.</param>
public virtual void Register<TMessage>(//TMessage接收的 类型
object recipient,//接收的对象一般是viewmodel
object token,//标记 ,细分类型下面的 分类。
bool receiveDerivedMessagesToo,// 是否也接收 (派生类的) 消息
Action<TMessage> action) {//当有消息来临的时候的 回调函数
var messageType = typeof(TMessage);
Dictionary<Type, List<WeakActionAndToken>> recipients;
//============================ 是否也接收 (派生类的) 消息
if (receiveDerivedMessagesToo) {
if (_recipientsOfSubclassesAction == null) {
_recipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsOfSubclassesAction;
}
// 默认是 false -即 不接收 (派生类的) 消息
else {
if (_recipientsStrictAction == null) {
_recipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsStrictAction;
}
//============================
List<WeakActionAndToken> list;
if (!recipients.ContainsKey(messageType)) { //如果不存在 List 就添加
list = new List<WeakActionAndToken>();
recipients.Add(messageType, list);
} else {
list = recipients[messageType];//存在就取出
}
// 新建一个 weakAction 弱引用 方法
var weakAction = new WeakAction<TMessage>(recipient, action);// new WeakAction<TMessage>(viewmodel, function);
var item = new WeakActionAndToken {
Action = weakAction,
Token = token
};
list.Add(item);
//清除已经被垃圾回收的对象
Cleanup();
}
/// Registers a recipient for a type of message TMessage.
/// 为T类型的参数 注册一个接受者,
/// The action parameter will be executed when a corresponding (相应的)
/// (当接收到) 参数action 这个方法将被执行
/// message is sent. See the receiveDerivedMessagesToo parameter
/// for details on how messages deriving from TMessage (or, if TMessage is an interface,
/// messages implementing TMessage) can be received too.
/// 是否 接收 接口的 派生类的 信息
/// <para>Registering a recipient does not create a hard reference to it,
/// so if this recipient is deleted, no memory leak is caused.</para>
/// </summary>
/// <typeparam name="TMessage">The type of message that the recipient registers
/// for.</typeparam>
/// <param name="recipient">The recipient that will receive the messages.</param>
/// <param name="token">A token(标记) for a messaging channel.
/// token 是一个 栏目的标记
/// If a recipient registers
/// using a token, and a sender sends a message using the same token, then this
/// 发送和接收方使用同一个标记 token接收 才能 接收到
/// message will be delivered to the recipient. Other recipients who did not
///
/// use a token when registering (or who used a different token) will not
/// get the message.
///
/// Similarly, messages sent without any token, or with a different
/// token, will not be delivered to that recipient.</param>
///
/// <param name="receiveDerivedMessagesToo">If true, message types deriving from
/// TMessage will also be transmitted to the recipient. For example, if a SendOrderMessage
/// and an ExecuteOrderMessage derive from OrderMessage, registering for OrderMessage
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
/// and ExecuteOrderMessage to the recipient that registered.
///
/// <para>Also, if TMessage is an interface, message types implementing TMessage will also be
/// transmitted to the recipient. For example, if a SendOrderMessage
/// and an ExecuteOrderMessage implement IOrderMessage, registering for IOrderMessage
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
/// and ExecuteOrderMessage to the recipient that registered.</para>
/// </param>
/// <param name="action">The action that will be executed when a message
/// of type TMessage is sent.</param>
public virtual void Register<TMessage>(//TMessage接收的 类型
object recipient,//接收的对象一般是viewmodel
object token,//标记 ,细分类型下面的 分类。
bool receiveDerivedMessagesToo,// 是否也接收 (派生类的) 消息
Action<TMessage> action) {//当有消息来临的时候的 回调函数
var messageType = typeof(TMessage);
Dictionary<Type, List<WeakActionAndToken>> recipients;
//============================ 是否也接收 (派生类的) 消息
if (receiveDerivedMessagesToo) {
if (_recipientsOfSubclassesAction == null) {
_recipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsOfSubclassesAction;
}
// 默认是 false -即 不接收 (派生类的) 消息
else {
if (_recipientsStrictAction == null) {
_recipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsStrictAction;
}
//============================
List<WeakActionAndToken> list;
if (!recipients.ContainsKey(messageType)) { //如果不存在 List 就添加
list = new List<WeakActionAndToken>();
recipients.Add(messageType, list);
} else {
list = recipients[messageType];//存在就取出
}
// 新建一个 weakAction 弱引用 方法
var weakAction = new WeakAction<TMessage>(recipient, action);// new WeakAction<TMessage>(viewmodel, function);
var item = new WeakActionAndToken {
Action = weakAction,
Token = token
};
list.Add(item);
//清除已经被垃圾回收的对象
Cleanup();
}