[CommunityToolkit.Mvvm个人总结]2.Messenger

本系列主要介绍微软社区工具包CommunityToolKit.Mvvm,是本人在观看B站UP主十月的寒流视频时的个人总结,真心感谢!学习C#的同学强力建议关注此UP,并观看其全部视频。

如何使用 CommunityToolkit.Mvvm 中的 Messenger 来进行 ViewModel 之间的通信_哔哩哔哩_bilibili

语言:C# 

IDE:LINQPad7.0,Microsoft Visual Studio Community 2022 

框架:WPF,.net 8.0


零、LINQPad

LINQPad是一个轻量级的C# 和 SQL 编写和测试工具,可用于代码片段的快速验证

下载链接:LINQPad v8.4.11 .NET开发操练场 - 『精品软件区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

一、定义和作用

Messenger的作用为搭建一个通道,为不同的ViewModel发送和接收消息。

二、自定义Messenger

再次感叹UP主的代码能力,膜拜!

var rec1 = new StringReceiver();
var rec2 = new NumberReceiver();
EventAggregator.Instance.Send(new StringMessage("hello world!"));
EventAggregator.Instance.Send(new StringMessage("goodby world!"));
EventAggregator.Instance.Send(new NumberMessage(123));

abstract class MessageReceiver<TMessage>
{
	protected MessageReceiver()
	{
		EventAggregator.Instance.Register<TMessage>(this, Receive);
	}

	public abstract void Receive(TMessage m);
}

class StringReceiver : MessageReceiver<StringMessage>
{
	public override void Receive(StringMessage message)
	{
		Console.WriteLine("String message received:" + message.ToString());
	}
}

class NumberReceiver : MessageReceiver<NumberMessage>
{
	public override void Receive(NumberMessage message)
	{
		Console.WriteLine("Number message received:" + message.ToString());
	}
}


record StringMessage(string Message);
record NumberMessage(int Value);

class EventAggregator
{
	public static readonly EventAggregator Instance = new EventAggregator();

	record MessageReceiver(object Receiver, Action<object> Method);

	private Dictionary<Type, List<MessageReceiver>> events = new Dictionary<Type, List<MessageReceiver>>();

	public void Register<TMessage>(object receiver, Action<TMessage> method)
	{
		var type = typeof(TMessage);
		if (!events.ContainsKey(type))
		{
			events[type] = new List<MessageReceiver>();
		}
		events[type].Add(item: new MessageReceiver(receiver, o => method((TMessage)o)));
	}

	public void Send<TMessage>(TMessage message)
	{
		var type = typeof(TMessage);
		if (!events.ContainsKey(type))
		{
			events[type] = new();
		}
		foreach (var rec in events[type])
		{
			rec.Method.Invoke(message);
		}
	}
}

输出结果:

String message received:StringMessage { Message = hello world! }
String message received:StringMessage { Message = goodby world! }
Number message received:NumberMessage { Value = 123 }

三、使用Toolkit Messenger 

ValueChangeMessage<T>可用于自定义类型的消息通知

PropertyChangedMessage<T>可用于属性更改时的消息通知

var rec = new ViewModel();
var rec2 = new ViewModel2();

rec2.Number = 10;
WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello world!"));

class ViewModel
{
	public ViewModel()
	{
		WeakReferenceMessenger.Default.Register<ValueChangedMessage<string>>(this, Receive);
		WeakReferenceMessenger.Default.Register<PropertyChangedMessage<int>>(this, Receive2);
	}

	private void Receive2(object recipient, PropertyChangedMessage<int> message)
	{
		message.Dump("Int message received");
	}

	private void Receive(object recipient, ValueChangedMessage<string> message)
	{
		message.Dump("String message received");
	}
}

class ViewModel2 : ObservableObject
{
	int number;
	public int Number
	{
		get { return number; }
		set
		{
			if (SetProperty(ref number, value))
			{
				WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<int>(this, nameof(Number), default, value));
			}
		}
	}
}

输出结果: 

四、RequestMessage 

RequestMessage带一个返回类型,类似回调,可回传一个值

var rec = new ReceiverViewModel();
var sdr = new SenderViewModel();

class ReceiverViewModel:ObservableObject,IRecipient<RequestMessage<string>>
{
	public ReceiverViewModel()
	{
		WeakReferenceMessenger.Default.Register(this);
	}
	
	public void Receive(RequestMessage<string> message)
	{
		"Request message Received.".Dump();
		message.Reply("Hello");
	}
}

class SenderViewModel
{
	public SenderViewModel()
	{
		var res = WeakReferenceMessenger.Default.Send(new RequestMessage<string>());
		res.Response.Dump("Respon received");
	}
}

运行结果:

Request message Received.
Respon received
Hello

五、Demo

实现效果为:

1.可输入Name,Class,Phone,点击Add New按钮后添加到DataGrid。

2.CheckBox可实现对Add New按钮属性IsEnabled的修改

3.在编辑Name/Class/Phone时,下方的TextBlock实时显示

完整代码见本文档附带的下载链接

六、总结

6.1 注册消息

6.1.1  方法:void Register<TMessage>(object recipient, MessageHandler<object, TMessage> handler) 

反编译:

public static void Register<TMessage>(this IMessenger messenger, object recipient, MessageHandler<object, TMessage> handler) where TMessage : class
{
	ArgumentNullException.ThrowIfNull(messenger, "messenger");
	ArgumentNullException.ThrowIfNull(recipient, "recipient");
	ArgumentNullException.ThrowIfNull(handler, "handler");
	messenger.Register(recipient, default(Unit), handler);
}

使用举例:

var rec = new ReceiveViewModel();

WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello"));

class ReceiveViewModel
{
	public ReceiveViewModel()
	{
		WeakReferenceMessenger.Default.Register<ValueChangedMessage<string>>(this, Receive);
	}

	void Receive(object recipient, ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} messsage has receive");
	}
}

 运行结果:

6.1.2  接口:interface IRecipient<in TMessage> where TMessage : class

反编译:

public interface IRecipient<in TMessage> where TMessage : class
{
	/// <summary>
	/// Receives a given <typeparamref name="TMessage" /> message instance.
	/// </summary>
	/// <param name="message">The message being received.</param>
	void Receive(TMessage message);
}

使用举例:

var rec = new ReceiveViewModel();
WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello"));

class ReceiveViewModel : IRecipient<ValueChangedMessage<string>>
{
	public ReceiveViewModel()
	{
		WeakReferenceMessenger.Default.Register(this);
	}

	public void Receive(ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} messsage has receive");
	}
}

 运行结果:

6.1.3 基类ObservableRecipient和接口 Recipient<in TMessage>

注意,需要在属性IsActive=true时才会接收到消息 

使用举例:

var rec = new ReceiveViewModel(){IsActive = true};
WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello"));

class ReceiveViewModel : ObservableRecipient, IRecipient<ValueChangedMessage<string>>
{
	public void Receive(ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} messsage has receive");
	}
}	

 运行结果:

 6.1.4 基类ObservableRecipient和方法OnActivated

注意,需要在属性IsActive=true时才会接收到消息 

使用举例

var rec = new ReceiveViewModel(){IsActive = true};
WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello"));

class ReceiveViewModel : ObservableRecipient
{
	protected override void OnActivated()
	{
		Messenger.Register<ValueChangedMessage<string>>(this, Receive);
	}

	void Receive(object recipient, ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} messsage has receive");
	}
}

运行结果:

6.2 发送消息

6.2.1 Send<TMessage>(TMessage message)

只要注册类型相同,就可接受到发送的消息

反编译:

public static TMessage Send<TMessage>(this IMessenger messenger, TMessage message) where TMessage : class
{
	ArgumentNullException.ThrowIfNull(messenger, "messenger");
	ArgumentNullException.ThrowIfNull(message, "message");
	return messenger.Send(message, default(Unit));
}

使用举例:

var rec1 = new ReceiverViewModel();
var rec2 = new ReceiverViewMode2();
WeakReferenceMessenger.Default.Send<string>("Hello");

class ReceiverViewModel : ObservableObject, IRecipient<string>
{
	public ReceiverViewModel()
	{
		WeakReferenceMessenger.Default.Register(this);
	}

	public void Receive(string message)
	{		
		message.Dump($"{GetType().Name} has received");
	}
}

class ReceiverViewMode2 : ObservableObject, IRecipient<string>
{
	public ReceiverViewMode2()
	{
		WeakReferenceMessenger.Default.Register(this);
	}

	public void Receive(string message)
	{
		message.Dump($"{GetType().Name} has received");
	}
}

运行结果:

ReceiverViewModel has received
Hello
ReceiverViewMode2 has received
Hello

 6.2.2 Send<TMessage>(TMessage message) where TMessage : class

只要注册类型相同,就可接受到发送的消息

反编译:

public static TMessage Send<TMessage>(this IMessenger messenger, TMessage message) where TMessage : class
{
	ArgumentNullException.ThrowIfNull(messenger, "messenger");
	ArgumentNullException.ThrowIfNull(message, "message");
	return messenger.Send(message, default(Unit));
}

使用举例:

var rec1 = new ReceiverViewModel1();
var rec2 = new ReceiverViewModel2();

WeakReferenceMessenger.Default.Send(new ValueChangedMessage<int>(123));
WeakReferenceMessenger.Default.Send(new ValueChangedMessage<string>("Hello"));

class ReceiverViewModel1 : ObservableObject, IRecipient<ValueChangedMessage<string>>
{
	public ReceiverViewModel1()
	{
		WeakReferenceMessenger.Default.Register(this);
	}
	
	public void Receive(ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} has received");
	}
}

class ReceiverViewModel2 : ObservableObject, IRecipient<ValueChangedMessage<string>>
{
	public ReceiverViewModel2()
	{
		WeakReferenceMessenger.Default.Register(this);
	}

	public void Receive(ValueChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} has received");
	}
}

运行结果:

6.2.3 TMessage Send<TMessage, TToken>(TMessage message, TToken token) where TMessage : class where TToken : IEquatable<TToken>

可通过注册的Token来区分通道,只会接收到发送的Token一致的消息

反编译:

TMessage Send<TMessage, TToken>(TMessage message, TToken token) where TMessage : class where TToken : IEquatable<TToken>;

使用举例:

IMessenger messenger = WeakReferenceMessenger.Default;

var l1 = new Listener(messenger, "A", m => $"l1 received:{m}".Dump());
var l2 = new Listener(messenger, "B", m => $"l2 received:{m}".Dump());

messenger.Send(new SimpleMessage("Hello"), "A");
messenger.Send(new SimpleMessage("World"), "B");

class Listener
{
	public Listener(IMessenger messenger, string channel, Action<string> response)
	{
		messenger.Register<SimpleMessage, string>(this, channel, (_,m)=> response(m.Content));
	}
}

record SimpleMessage(string Content);

运行结果 

l1 received:Hello
l2 received:World

6.2.4 PropertyChangedMessage<T>

使用举例:

var rec = new ReceiveViewModel() { IsActive = true };
var sender = new SendViewModel();
sender.Data = "Hello";

class ReceiveViewModel : ObservableRecipient, IRecipient<PropertyChangedMessage<string>>
{
	public void Receive(PropertyChangedMessage<string> message)
	{
		message.Dump($"{GetType().Name} has received");
	}
}

partial class SendViewModel : ObservableObject
{
	private string data;
	
	public string Data
	{
		get => data;
		set 
		{
			if (SetProperty(ref data, value))
			{
				WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(Data), default, value));
			}
		}
	}
}

运行结果:

6.3 接收消息

在本文中的代码中已出现多次,不再赘述。

6.4 特殊Attribute

6.4.1 NotifyPropertyChangedRecipients

如果在继承自 ObservableRecipient 的类型中声明属性,则可以使用 NotifyPropertyChangedRecipients 特性指示生成器还要插入代码,以针对属性更改发送一则说明属性已更改的消息。

使用举例:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging.Messages;
using CommunityToolkit.Mvvm.Messaging;

var rec1 = new ReceiveViewModel1() { IsActive = true };
var rec2 = new ReceiveViewModel2() { IsActive = true };
var sender = new SendViewModel();
sender.Data = "Hello";


class ReceiveViewModel1 : ObservableRecipient, IRecipient<PropertyChangedMessage<string>>
{
    public void Receive(PropertyChangedMessage<string> message)
    {
        Console.WriteLine($"{GetType().Name} has received");
    }
}

class ReceiveViewModel2 : ObservableRecipient, IRecipient<PropertyChangedMessage<string>>
{
    public void Receive(PropertyChangedMessage<string> message)
    {
        Console.WriteLine($"{GetType().Name} has received");
    }
}


partial class SendViewModel : ObservableRecipient
{
    [ObservableProperty]
    [NotifyPropertyChangedRecipients]
    private string? data;
}

运行结果:

ReceiveViewModel1 has received
ReceiveViewModel2 has received

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值