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

相关推荐
吾日三省吾码4 小时前
JVM 性能调优
java
LNTON羚通4 小时前
摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现
算法·目标检测·音视频·监控·视频监控
弗拉唐5 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi776 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3436 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀6 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
哭泣的眼泪4086 小时前
解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
python·算法·django·virtualenv·pygame
蓝黑20206 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深6 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++