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

相关推荐
weixin_462428479 分钟前
使用 Caffeine 缓存并在业务方法上通过注解实现每3到5秒更新缓存
java·缓存
程序媛小果11 分钟前
基于java+SpringBoot+Vue的桂林旅游景点导游平台设计与实现
java·vue.js·spring boot
骑鱼过海的猫12313 分钟前
【java】java通过s3访问ceph报错
java·ceph·iphone
杨充19 分钟前
13.观察者模式设计思想
java·redis·观察者模式
Lizhihao_21 分钟前
JAVA-队列
java·开发语言
算法歌者23 分钟前
[算法]入门1.矩阵转置
算法
喵叔哟30 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟30 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk33 分钟前
maven环境搭建
java·maven
林开落L38 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode