- 在VisualStudio中部署GDAL库的C++版本(包括SQLite、PROJ等依赖)
- Android开机流程介绍
- STM32CubeMX教程31USB_DEVICE-HID外设_模拟键盘或鼠标
- 深入浅出Java多线程(五):线程间通信
MediatR是一款进程内的消息订阅、发布框架,可实现请求/响应、命令、查询、通知和事件的消息传递,解耦了消息处理器和消息之间耦合。提供了Send方法用于发布到单个处理程序、Publish方法发布到多个处理程序,使用起来非常方便。目前支持 .NET Framework 、.NET Stardand、.NETCore等版本,可跨平台使用。本篇随笔介绍在Winform系统开发中,使用MediatR来实现类似事件总线的消息处理.
MediatR的GitHub项目地址:https://github.com/jbogard/MediatR 。
MediatR的各种场景使用代码:https://github.com/jbogard/MediatR/wiki 。
如果我们在VS开发项目,我们在Nugget上找到对应模块,直接添加到项目引用即可,如下所示.
MediatR使用 Microsoft.Extensions.DependencyInjection.Abstractions 来 注入服务处理,我们使用MediatR的时候,首先需要构造ServiceCollection,然后添加配置到其中.
// IServiceCollection负责注册 IServiceCollection services = new ServiceCollection(); //注册MediatR服务,用于测试MediatR的服务 services.AddMediatR(cfg => { cfg.RegisterServicesFromAssembly(typeof(Portal).Assembly); });
使用注入服务的时候,我们需要获得其中的ServiceProvider,如下通过BuildServiceProvider 获得该对象.
IServiceProvider provider = services.BuildServiceProvider();
然后我们创建一个静态类来存储这个对象.
//存储全局IServiceProvider的接口实例, 便于后续获得接口实例 ServiceLocator.ConfigService(provider);
其中静态类 ServiceLocator 的代码如下所示.
/// <summary> /// 全局存储IServiceProvider /// </summary> public class ServiceLocator { /// <summary> /// IOC中的IServiceProvider对象接口 /// </summary> public static IServiceProvider SerivcePovider { get; private set; } /// <summary> /// 赋值IServiceProvider到静态变量中 /// </summary> /// <param name="provider">IServiceProvider对象接口</param> public static void ConfigService(IServiceProvider provider) { SerivcePovider = provider; } /// <summary> /// 获取指定服务接口实例 /// </summary> /// <returns></returns> public static T GetService<T>() { return SerivcePovider.GetService<T>(); } }
后面我们就可以通过该静态类的 GetService<T>() 方法获取对应的注入接口IMediator,我们需要利用该接口来发送Send请求/应答命令或者发布Publish消息的处理。例如我们在窗体对象中定义该接口,用于实际的相关命令、消息的处理.
public partial class TestMediatR : BaseForm { private readonly IMediator _mediator; public TestMediatR() { InitializeComponent(); _mediator = ServiceLocator.GetService<IMediator>(); }
。
MediatR是一个跨平台通过一种进程内消息传递机制,进行请求/响应、命令、查询、通知和事件的消息传递,并通过C#泛型来支持消息的智能调度,其目的是消息发送和消息处理的解耦。它支持以单播和多播形式使用同步或异步的模式来发布消息,创建和侦听事件。它主要的几个对象:
IMediator:主要提供Send与Publish方法,需要执行的命令都是通过这两个方法实现 。
IRequest、IRequest<T>:命令查询 | 处理类所继承的接口,一个有返回类型,一个无返回类型,一个查询对应一个处理类,程序集只认第一个扫描到的类.
IRequestHandler<in TRequest,TResponse>(实现Handle方法) :命令处理接口。命令查询 | 处理类继承它,也可以继承AsyncRequestHandler(实现抽象Handle方法)、RequestHandler(实现抽象Handle方法)接口 。
INotification:命令查询 | 处理类所继承的接口这个没有返回,与IRequest不通的是可以对于多个处理类.
INotificationHandler<in TNotification>:与IRequestHandler一样的只不过这是INotification的处理接口.
Request/Response模式对象定义 。
/// <summary> /// 请求类 /// </summary> public class RetrieveInfoCommandRequest : IRequest<RetrieveInfoCommandResponse> { public string Text { get; set; } } /// <summary> /// 回应消息 /// </summary> public class RetrieveInfoCommandResponse { public string OutputMessage { get; set; } } /// <summary> /// 请求应答处理类 /// </summary> public class RetrieveInfoCommandHandler : IRequestHandler<RetrieveInfoCommandRequest, RetrieveInfoCommandResponse> { public async Task<RetrieveInfoCommandResponse> Handle(RetrieveInfoCommandRequest request, CancellationToken cancellationToken) { var response = new RetrieveInfoCommandResponse(); response.OutputMessage = $"This is an example of MediatR using {request.Text}"; return response; } }
例如我们根据这个请求、应答的消息协议,以及定义的处理Handler类(唯一一个),我们可以设计一个Winform界面来测试消息的处理.
界面的代码如下所示.
/// <summary> /// 测试MediatR的窗体例子 /// </summary> public partial class TestMediatR : BaseForm { private readonly IMediator _mediator; public TestMediatR() { InitializeComponent(); _mediator = ServiceLocator.GetService<IMediator>(); } /// <summary> /// 使用请求、应答的消息进行测试,获得返回结果后输出显示 /// </summary> private async void btnSend_Click(object sender, EventArgs e) { //应答处理 var outputMessage = await _mediator.Send(new RetrieveInfoCommandRequest { Text = this.txtSend.Text }); Console.WriteLine(outputMessage.OutputMessage); this.txtReceived.AppendText(outputMessage.OutputMessage + Environment.NewLine); }
上面的命令消息方式,有返回值,如果不需要返回值,也可以采用这种一一应答的方式,那么定义的时候,继承IRequest接口即可.
public class OneWay : IRequest { } public class OneWayHandler : IRequestHandler<OneWay> { public Task Handle(OneWay request, CancellationToken cancellationToken) { // do work return Task.CompletedTask; } }
。
Notification 消息通知模式 。
如果我们需要类似事件多播的处理,也就是常规的消息通知处理,我们采用INotification方式.
Notification模式将消息发布给多个处理程序,消息的处理没有返回值.
/// <summary> /// 通知类 /// </summary> public class MyNotification : INotification { public string Message { get; } public MyNotification(string message) { Message = message; } } /// <summary> /// Notification处理程序-模块1 /// </summary> public class MyNotifyHandler : INotificationHandler<MyNotification> { public Task Handle(MyNotification notification, CancellationToken cancellationToken) { var message = "模块1-收到消息:" + notification.Message; //MessageDxUtil.ShowTips(message); //提示消息 var alert = new AlertControl(); alert.FormLocation = AlertFormLocation.TopRight; alert.AutoFormDelay = 3000; alert.Show(Portal.gc.MainDialog, message, message); // 处理通知 Console.WriteLine($"Notification处理程序-模块1-收到消息: {notification.Message}"); return Task.CompletedTask; } } /// <summary> /// Notification处理程序-模块2 /// </summary> public class MySecondNotifyHandler : INotificationHandler<MyNotification> { public Task Handle(MyNotification notification, CancellationToken cancellationToken) { var message = "模块2-收到消息:" + notification.Message; //MessageDxUtil.ShowTips(message); //提示消息 var alert = new AlertControl(); alert.FormLocation = AlertFormLocation.TopRight; alert.AutoFormDelay = 3000; alert.Show(Portal.gc.MainDialog, message, message); // 处理通知 Console.WriteLine($"Notification处理程序-模块2-收到消息: {notification.Message}"); return Task.CompletedTask; } }
我们在界面上发布消息的代码如下所示.
private async void btnNotify_Click(object sender, EventArgs e) { //发布消息 await _mediator.Publish(new MyNotification(this.txtSend.Text)); }
可以看到在控制台和UI上我们的都有测试消息的输出.
默认情况下,MediatR的消息发布是一个一个执行的,即便是返回Task的情况,也是使用await等待上一个执行完成后才进行下一个的调用。如果需要使用并行的方法进行调用,可以进行定制,具体可参考官方示例:MediatR.Examples.PublishStrategies.
对于MediatR来说,无论是发送IRequest类型消息,还是发布INotification类型消息,都是异步的。这里需要特别留意,即使你使用的是同步的消息处理程序,对于消息发布来说,都是异步的,与你的处理程序是同步或异步无关.
详细的介绍,可以参考官方的案例介绍:https://github.com/jbogard/MediatR/wiki.
。
对于WPF,其实也是类似采用该组件实现事件、消息的处理的,不过如果我们采用MVVM的框架设计模式,可以采用MVVM(微软的 CommunityToolkit.Mvvm的组件包)的内置的消息处理模式,我在随笔《使用WPF开发自定义用户控件,以及实现相关自定义事件的处理》有相关的介绍.
CommunityToolkit.Mvvm (又名 MVVM 工具包,以前名为 Microsoft.Toolkit.Mvvm) 是一个现代、快速且模块化的 MVVM 库。官网介绍地址:https://learn.microsoft.com/zh-cn/dotnet/communitytoolkit/mvvm/ 。
利用MVVM推送一条消息,如下代码所示.
//发送MVVM消息信息通知方式(一) WeakReferenceMessenger.Default.Send(new ClickEventMessage(eventData));
而其中 ClickEventMessage 是我们根据要求定义的一个消息对象类,如下代码所示.
完整的Command命令如下所示.
/// <summary> /// 双击触发MVVM消息通知 /// </summary> /// <param name="typeName">处理类型:Number、Animal、WuHan</param> /// <returns></returns> [RelayCommand] private async Task DoubleClick(string typeName) { var clickType = ClickEventType.Number; var clickValue = this.Number; ..............//处理不同typeName值逻辑//事件数据 var eventData = new ClickEventData(clickType, clickValue); //发送MVVM消息信息通知方式(一) WeakReferenceMessenger.Default.Send(new ClickEventMessage(eventData)); }
通过这样的消息发送,就需要有个地方来接收这个信息的,我们在需要处理事件的父窗口中拦截处理消息即可.
//处理MVVM的消息通知 WeakReferenceMessenger.Default.Register<ClickEventMessage>(this, (r, m) => { var data = m.Value; var list = ControlHelper.FindVisualChildren<LotteryItemControl>(this.listControl); foreach (var lottery in list) { lottery.SetSelected(data); } });
从而实现了WPF消息的发送和应答处理.
另外,我在随笔《使用 FastEndpoints 来垂直切割Web API的控制器方法》介绍的FastEndpoints 处理机制,也是类似这样的模式,有兴趣可以了解一下FastEndpoints 的处理.
。
最后此篇关于在Winform系统开发中,使用MediatR来实现类似事件总线的消息处理的文章就讲到这里了,如果你想了解更多关于在Winform系统开发中,使用MediatR来实现类似事件总线的消息处理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!