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

相关推荐

  1. C#MVVM 工具包——Messenger

    2024-05-01 17:58:03       32 阅读
  2. MVVM框架下Mapster工具包

    2024-05-01 17:58:03       33 阅读
  3. C. Messenger in MAC - 堆优化枚举

    2024-05-01 17:58:03       43 阅读
  4. Vue中MVVM

    2024-05-01 17:58:03       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-01 17:58:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-01 17:58:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-05-01 17:58:03       87 阅读
  4. Python语言-面向对象

    2024-05-01 17:58:03       96 阅读

热门阅读

  1. 实现C#无标题栏窗体拖动

    2024-05-01 17:58:03       30 阅读
  2. Python模块方法总结

    2024-05-01 17:58:03       28 阅读
  3. docker seata

    2024-05-01 17:58:03       32 阅读
  4. Hadoop生态系统的核心组件探索

    2024-05-01 17:58:03       23 阅读
  5. RabbitMQ Transport indicated EOF 总结

    2024-05-01 17:58:03       32 阅读
  6. oracle的sqlplus默认会执行的脚本

    2024-05-01 17:58:03       33 阅读
  7. 访问一个 HTTP 接口却收到 HTTPS 错误的响应

    2024-05-01 17:58:03       33 阅读
  8. python实现RGB模式颜色转换器

    2024-05-01 17:58:03       29 阅读
  9. Centos7安装完ifconfig命令出错:bash: command not found

    2024-05-01 17:58:03       31 阅读
  10. k8s pod 镜像拉取策略

    2024-05-01 17:58:03       27 阅读
  11. Python解释器:编程界的“翻译官”

    2024-05-01 17:58:03       30 阅读
  12. ps基础学习笔记-颜色模式

    2024-05-01 17:58:03       29 阅读
  13. 排序试题(一)

    2024-05-01 17:58:03       34 阅读