C#的MVVM 工具包——Messenger

C#的MVVM 工具包------Messenger

Messenger 模式是一种设计模式,它允许应用程序的不同部分之间进行松耦合的通信。在 MVVM 架构中,这种模式尤为重要,因为它可以帮助实现视图(View)和视图模型(ViewModel)之间的清晰分离。MVVM 工具包提供两种现用的实现:WeakReferenceMessenger 和 StrongReferenceMessenger,前者在内部使用弱引用,为收件人提供自动内存管理,而后者使用强引用,并要求开发人员在不再需要收件人时手动取消订阅收件人,虽然使起来稍显繁琐,但这一点换来的是提供更好的性能,而且内存使用量要少得多。


WeakReferenceMessenger

CommunityToolkit.Mvvm.Messaging命名空间下的一个实现,它使用弱引用(Weak References)来管理消息的发送者和接收者,从而避免内存泄漏并提高性能。

  1. 工作原理

WeakReferenceMessenger的核心工作原理基于弱引用的概念。弱引用允许一个对象被垃圾回收器回收,即使有其他对象引用它。在 WeakReferenceMessenger中,这意味着消息的发送者和接收者之间的引用是弱的,因此不会阻止它们被垃圾回收器回收。

当发送者发送消息时,WeakReferenceMessenger会将消息存储起来,并尝试找到所有注册接收该类型消息的接收者。由于使用弱引用,如果接收者被垃圾回收器回收,它将不会收到消息,从而避免了内存泄漏的风险。

  1. 主要特点

弱引用:使用弱引用来跟踪消息的发送者和接收者,减少内存占用和潜在的内存泄漏。

线程安全:消息的发送和接收是线程安全的,可以在多线程环境中使用。

灵活性:支持多种消息类型和通道,允许不同的模块或组件之间进行特定的通信。

解耦:发送者和接收者不需要直接引用对方,它们只需要注册到 WeakReferenceMessenger`即可。

  1. 使用示例

假设正在开发一个具有主界面和设置界面的应用程序。主界面允许用户更改主题设置,而设置界面监听这些更改并相应地更新界面。

定义消息类型:

复制代码
public class ThemeChangedMessage
{
  public string NewTheme { get; set; }
  public ThemeChangedMessage(string newTheme)
  {
  	NewTheme = newTheme;
  }
}

创建消息发送者:

在主界面的 ViewModel 中,我们定义一个方法来更改主题,并发送 ThemeChangedMessage。

复制代码
public class MainViewModel
{
  public void ChangeTheme(string newTheme)
  {
    // 执行更改主题的逻辑...
    // 发送主题更改消息
    WeakReferenceMessenger.Default.Send(new ThemeChangedMessage(newTheme));
  }
}

创建消息接收者:

在设置界面的 ViewModel 中,注册为ThemeChangedMessage的接收者,并处理消息。

复制代码
public class SettingsViewModel : ObservableRecipient
{
    public SettingsViewModel()
    {
        // 注册接收 ThemeChangedMessage
        WeakReferenceMessenger.Default.Register<ThemeChangedMessage>(this, HandleThemeChanged);
    }

    private void HandleThemeChanged(ThemeChangedMessage message)
    {
        // 更新设置界面以反映新主题
        // 例如,更改控件的颜色或字体
    }

    protected override void OnDeactivated()
    {
        // 取消注册消息接收,避免内存泄漏
        WeakReferenceMessenger.Default.UnregisterAll(this);
    }
}

处理消息:

当用户在主界面更改主题时,MainViewModel会发送一个ThemeChangedMessage。WeakReferenceMessenger会找到SettingsViewModel因为它注册了对此类消息的兴趣),并调用`HandleThemeChanged 方法来处理消息。

  1. 性能考虑

使用 WeakReferenceMessenger时,需要注意以下几点以确保最佳性能:

  • 避免长时间持有消息接收者:如果消息接收者不再需要,应该取消注册,以允许垃圾回收器回收它。
  • -合理使用消息通道:通过为不同的消息类型定义通道,可以减少消息处理的开销,并提高应用程序的响应性。
  • 优化消息处理逻辑:确保消息处理逻辑尽可能高效,避免在消息处理中执行耗时的操作。

StrongReferenceMessenger

StrongReferenceMessenger提供了一种使用强引用来跟踪注册的收件人的方法。

  1. 工作原理

StrongReferenceMessenger是IMessenger接口的一种实现,它使用强引用来维护消息发送者和接收者之间的联系。这意味着,只要收件人没有被显式注销,它就会一直被StrongReferenceMessenger保持活动状态,即使没有其他引用指向该收件人。这种机制确保了消息能够可靠地传递给收件人,但也意味着开发者需要负责管理收件人的生命周期,以避免潜在的内存泄漏问题。

  1. 注册与发送消息

使用StrongReferenceMessenger时,首先需要注册消息接收者。注册可以通过两种方式进行:使用IRecipient<TMessage>接口或MessageHandler<TRecipient, TMessage>委托。

使用IRecipient<TMessage>接口

接收者需要实现IRecipient<TMessage>接口,并提供一个Receive(TMessage)方法来处理接收到的消息。

复制代码
public class MyRecipient : IRecipient<LoggedInUserChangedMessage>
{
    public void Receive(LoggedInUserChangedMessage message)
    {
        // 处理消息...
    }
}

注册和发送消息的示例:

复制代码
// 注册消息接收者
StrongReferenceMessenger.Default.Register<MyRecipient, LoggedInUserChangedMessage>(myRecipient);

// 发送消息
StrongReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

使用MessageHandler<TRecipient, TMessage>委托

这种方式允许你直接使用lambda表达式或方法组来作为消息处理程序。

复制代码
// 注册消息处理程序
StrongReferenceMessenger.Default.Register<LoggedInUserChangedMessage>((message) => {
    // 处理消息...
});

// 发送消息
StrongReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));
  1. 取消注册

由于StrongReferenceMessenger使用强引用,因此当不再需要接收消息时,必须显式取消注册收件人或处理程序。这可以通过以下几种方式完成:按消息类型取消注册

复制代码
// 取消注册特定类型的消息
StrongReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage>(myRecipient);

按消息类型和通道取消注册

复制代码
// 取消注册特定通道的特定类型消息
StrongReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage, int>(myRecipient, channelToken);

取消注册所有消息

复制代码
// 取消注册所有消息,适用于所有通道
StrongReferenceMessenger.Default.UnregisterAll(myRecipient);
  1. 应用示例

假设正在开发一个具有用户登录功能的应用程序。当用户登录成功后,我们需要更新应用程序的不同部分,例如更新用户信息显示、加载新的用户配置文件图像等。我们可以使用StrongReferenceMessenger来实现这一跨组件通信的需求。

定义消息类型

复制代码
public class LoggedInUserChangedMessage : ValueChangedMessage<User>
{
    public LoggedInUserChangedMessage(User user) : base(user)
    {
    }
}

注册消息接收者

复制代码
public class UserViewModel
{
    public UserViewModel()
    {
        // 注册登录消息
        StrongReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this, (r, m) =>
        {
            // 更新用户信息
            this.CurrentUser = m.NewValue;
        });
    }
}

发送消息

复制代码
public class LoginViewModel
{
    public async Task LoginAsync(string username, string password)
    {
        // 假设这里有验证用户凭据的逻辑
        User user = ValidateCredentials(username, password);

        // 用户登录成功,发送登录消息
        StrongReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));
    }
}

处理消息

复制代码
public class UserProfileViewModel : IRecipient<LoggedInUserChangedMessage>
{
    public void Receive(LoggedInUserChangedMessage message)
    {
        // 更新用户的配置文件图像
        this.UserProfileImage = message.NewValue.AvatarUrl;
    }
}

总结

Messenger是.NET社区CommunityToolkit.Mvvm工具包中提供的一种消息传递机制,它允许应用程序中的不同组件之间进行松耦合的通信,而无需直接引用对方,降低了组件之间的依赖性,提高代码的可维护性和灵活性。在 MVVM 架构中,这种模式尤其有用,它支持视图和视图模型之间的清晰分离,提高应用程序的性能和可维护性,同时保持了它们之间通信的流畅和高效。

Messenger作为一个强大且灵活的消息传递解决方案,将有助于构建更加健壮和可扩展的应用程序。

相关推荐
云惠科技(SEO)14 分钟前
泛目录站群技术架构演进观察:2025年PHP+Java混合方案实战笔记
java·人工智能·搜索引擎
coder777723 分钟前
js逆向分享
javascript·爬虫·python·算法·安全
Eugene__Chen39 分钟前
JVM详解(曼波脑图版)
jvm
冠位观测者1 小时前
【Leetcode 每日一题 - 补卡】1534. 统计好三元组
数据结构·算法·leetcode
牛马baby1 小时前
Springboot 自动装配原理是什么?SPI 原理又是什么?
java·spring boot·后端
明月看潮生1 小时前
青少年编程与数学 02-016 Python数据结构与算法 25课题、量子算法
python·算法·青少年编程·量子计算·编程与数学
小小深1 小时前
了解JVM
java·jvm
Sunlight_7771 小时前
第五章 SQLite数据库:1、SQLite 基础语法及使用案例
java·linux·服务器·jvm·数据库·tcp/ip·sqlite
JNU freshman1 小时前
C. Robin Hood in Town思考与理解
算法
JhonKI1 小时前
【从零实现高并发内存池】内存池整体框架设计 及 thread cache实现
java·redis·缓存