• Caliburn.Micro框架学习笔记——事件总线机制


    Caliburn.Micro 提供了一个称为事件聚合器(Event Aggregator)的事件总线机制,它可以用于实现视图模型之间的解耦和通信。事件聚合器允许不同的视图模型通过发布和订阅事件来进行通信,而不需要彼此直接引用。

    何时使用这个功能

    事件总线机制适用于以下场景:

    • 解耦视图模型之间的通信

      • 当不同的视图模型需要通信时,但不希望它们直接相互引用时,可以使用事件总线机制来实现解耦。
    • 松散耦合的事件通知

      • 当某个事件的发生需要通知多个订阅者时,可以使用事件总线机制来实现松散耦合的事件通知。
    • 跨越模块的通信

      • 当应用程序具有多个模块或组件,并且需要在它们之间进行通信时,可以使用事件总线机制来实现模块之间的松散耦合。

    事件总线机制的对象

    1. 事件聚合器(Event Aggregator)

      • 事件聚合器是 Caliburn.Micro 中的核心组件,用于管理事件的发布和订阅。它允许不同的视图模型之间进行解耦的通信。
    2. 事件(Event)

      • 事件是一个简单的类,通常包含一些数据,用于在视图模型之间传递信息。事件可以是自定义的,根据需要定义不同的事件类型。
    3. 订阅者(Subscriber)

      • 订阅者是订阅特定事件的视图模型或其他对象。一旦订阅了事件,当该事件被发布时,订阅者将收到通知并执行相应的操作。

    实现caliburn.micro事件总线机制的步骤 

    1. 创建事件

      • 定义一个事件类,通常包含需要传递的数据。
    2. 发布事件

      • 在一个视图模型中发布(触发)事件,以通知其他订阅者。
    3. 订阅事件

      • 在其他视图模型中订阅感兴趣的事件。一旦订阅了事件,当该事件被发布时,订阅者将收到通知。

    具体操作实例

    配置事件聚合器

    首先,需要在 AppBootstrapper 中注册事件聚合器,以便在应用程序中使用

    1. public class Startup : BootstrapperBase
    2. {
    3. private SimpleContainer _container;//简单容器
    4. public Startup()
    5. {
    6. this.Initialize();
    7. }
    8. protected override async void OnStartup(object sender, StartupEventArgs e)
    9. {
    10. await DisplayRootViewForAsync();
    11. }
    12. protected override void Configure()
    13. {
    14. _container = new SimpleContainer();
    15. this._container.Instance(this._container);
    16. this._container
    17. .Singleton()//容器注入事件聚合器
    18. .Singleton();
    19. this._container
    20. .PerRequest();
    21. }
    22. protected override object GetInstance(Type service, string key)
    23. {
    24. return this._container.GetInstance(service, key);
    25. }
    26. }

    定义事件类

    定义一个事件类,用于传递需要的信息。

    1. public class Message
    2. {
    3. public Action<int> Callback { get; set; }
    4. }

    发布事件

    在需要发布事件的视图模型中,通过 IEventAggregator 发布事件。

    1. public class MainViewModel : IHandle<Message>, IHandle<string>
    2. {
    3. IEventAggregator eventAggregator;
    4. public MainViewModel(IEventAggregator ea)
    5. {
    6. eventAggregator = ea;
    7. }
    8. public async void Send()
    9. {
    10. //点击按钮的时候执行发布动作
    11. // 消息内容是根据消息类型进行匹配
    12. // ** 最终的执行线程并不是由发布决定的,由订阅者决定 **
    13. Message message = new Message();
    14. message.Callback = new Action<int>(OnCallback);
    15. await eventAggregator.PublishOnCurrentThreadAsync(message);//发布此事件
    16. }
    17. 此时回调函数有,用这个目的是为了不想再多建立一个viewmodel了,读者可以自己建一个view和viewmodel,这样就不需要这么写了。但是如果想知道订阅方发送回来的内容,也可以这个写。
    18. private void OnCallback(int value)
    19. {
    20. }
    21. }

     订阅事件

    在其他需要接收事件的视图模型中,订阅并处理该事件。这里直接用这个viewModel对应的View来进行订阅。偷个懒。

    1. public partial class MainView : Window, IHandle<string>, IHandle<Message>
    2. {
    3. public MainView()
    4. {
    5. InitializeComponent();
    6. // 这种方式获取注入对象实例,不仅在View中可以使用,VM中也可以使用
    7. IoC.Get()
    8. .SubscribeOnUIThread(this);
    9. }
    10. public Task HandleAsync(string message, CancellationToken cancellationToken)
    11. {
    12. return Task.CompletedTask;
    13. }
    14. public Task HandleAsync(Message message, CancellationToken cancellationToken)
    15. {
    16. // 有数据返回到发布方
    17. // 被动触发,触发之后,经过逻辑处理,希望有个数据返回到调用方
    18. int value = 789;
    19. message.Callback(value);
    20. return Task.CompletedTask;
    21. }
    22. }

    其中订阅过后,此时一旦进入到此订阅方,直接自己执行这两个Task,因为其继承了IHandle,它会根据参数类型去自动匹配,然后因为在发布者当中使用了参数回调,因此可以知道此时从订阅者传回来的处理后的消息。

    另外可以从打断点可知,事件的执行线程由订阅者决定。其中包括如下订阅方式——>

    // 永远在后台线程执行SubscribeOnBackgroundThread
    //eventAggregator.SubscribeOnBackgroundThread(this);
    // 在发布者的线程中执行SubscribeOnPublishedThread
    //eventAggregator.SubscribeOnPublishedThread(this);
    // 永远在UI线程执行SubscribeOnUIThread
    //eventAggregator.SubscribeOnUIThread(this);

    另外一个需要注意的是

    • 订阅者在不再需要时应调用 eventAggregator.Unsubscribe(this) 取消订阅,以防止内存泄漏。

     总结

    以上就是caliburn.micro的事件总线机制,好处会在多个view之间需要传递参数时,通过viewModel层继承IHandle进行事件发布,通过接收方继承IHandle进行事件订阅,可以很好的实现不同模块之间的通信。

  • 相关阅读:
    SpringBoot 整合 ActiveMQ、RabbitMQ(direct、topic模式)、RocketMQ详解代码示例
    SparkSQL的编程题
    【RTT驱动框架分析】-硬件定时器应用笔记和源码分析
    Vue.js 报错:Cannot read property ‘validate‘ of undefined“
    分布式事务解决方案详解
    Golang洗牌算法(Golang乱序算法)
    217. 存在重复元素、Leetcode的Python实现
    LeetCode只出现一次的数字
    【23种设计模式】装饰器模式
    车载摄像头CAM
  • 原文地址:https://blog.csdn.net/weixin_42031602/article/details/139371642