WPF 消息传递简明教程
0、说明
参考:https://www.cnblogs.com/cdaniu/p/16852620.html
使用包:CommunityToolkit.Mvvm(8.1.0)
1、订阅
让需要使用消息的 ViewModel 继承 ObservableRecipient,构造函数中设置 IsActive=true:
重写 OnActivated () 和 OnDeactivated () 方法:
#region 消息处理 /// <summary> /// 注册消息接收 /// </summary> protected override void OnActivated() { WeakReferenceMessenger.Default.Register<MainWindowViewModel, MyMessage, string>(this, nameof(MyMessage), OnReceiveMessage); } /// <summary> /// 收到消息时的处理方法 /// </summary> /// <param name="recipient">接收者</param> /// <param name="message">消息</param> private void OnReceiveMessage(MainWindowViewModel recipient, MyMessage message) { //处理逻辑; } /// <summary> /// 注销消息接收 /// </summary> protected override void OnDeactivated() { base.OnDeactivated(); WeakReferenceMessenger.Default.Unregister<MyMessage, string>(this, nameof(MyMessage)); } #endregion
解释:
2、发送消息
var message = new MyMessage() { //属性赋值, }; WeakReferenceMessenger.Default.Send(message, nameof(MyMessage));
3、注意事项
主要用法就是上面两点,还是挺简单的,但是网上的文章却看得人云里雾里的。这一节说一些注意事项。
3.1、消息类型不要混用
消息类应当是每个消息专用的,推荐使用 sealed 标记:
3.2、订阅要在发送之前执行
这一条大家可能会觉得这有什么好提醒的,本来就要这样啊。但是,实际写的时候,还是容易发生执行到发送的逻辑时,订阅的那部分代码实际还没执行,通常就是那个 ViewModel 还没出生呢。不过这个也很好排查出来,一般出现发了消息,但是消息处理方法那里没反应,就是这个问题了。解决方法就是让订阅的对象先生成出来即可,只不过有的时候这样可能没什么道理,大家有更好的方法,欢迎交流。
就说这么多吧,感谢阅读。
4、简化版(去除令牌)
[此节添加于 2023 年 8 月 30 日]
由于之前重写的 OnDeactivated 方法中调用了基类方法,而基类方法中已经是注销当前类的对象的所有注册消息了:
所以要么不调用基类方法,要么直接不重写此方法,本节选择后者(直接移除此重写)。
然后是注册消息的简化,本节是去除了 令牌 Token(前文称之为通道):
自然地,发送的时候也可以去除令牌。
所以,除了保持 “继承 ObservableRecipient,构造函数中设置 IsActive=true” 之外,其余的可简化为如下代码(去除令牌):
#region 消息处理 /// <summary> /// 注册消息接收 /// </summary> protected override void OnActivated() { WeakReferenceMessenger.Default.Register<MainViewModel, MyMessage>(this, OnReceiveMessage); } /// <summary> /// 收到消息时的处理方法 /// </summary> /// <param name="recipient">接收者</param> /// <param name="message">消息</param> private void OnReceiveMessage(MainViewModel recipient, MyMessage message) { //处理逻辑; Dispatcher.CurrentDispatcher.Invoke(() => { //可能需要这样调度回 UI 线程; }); } #endregion //消息发送(一般在其它类中) WeakReferenceMessenger.Default.Send(new MyMessage());
然后看看类库中 Register 方法的重载:
可以看出关键的只需要 TMessage 就行了,也就是说接收者(或者称之为注册者) TRecipient 也是可以省略的,关于这一点,本次暂未研究,之后研究了再和大家分享。
原创文章,转载请注明: 转载自 独立观察员(dlgcy.com)
本文链接地址: [WPF 消息传递简明教程](https://dlgcy.com/toolkit-mvvm-message/)
关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章
发表评论