背景:
官网只介绍了推荐适用ReactiveUI,没有过多的案例介绍,对于初入桌面应用开发的小白极其不友好。
本文介绍在Avalonia应用中通过ReactiveUI中的MessageBus进行跨组件通信.
假设需求案例:
MainWindowViewModel中发送消息,AnotherViewModel中接收MainWindowViewModel发送的消息。
安装依赖:
Avalonia.ReactiveUI
Microsoft.Extensions.DependencyInjection(DI依赖注入,非此案例必须)

实现思路:
- 使用MessageBus.SendMessage()发送消息;
 - 需要接收消息的组件使用MessageBus.Listen()订阅消息;
 
关键代码:
- 在App.axaml.cs中注入MessageBus(使用DI);
 
private IServiceProvider _serviceProvider;
public override void Initialize()
{
    AvaloniaXamlLoader.Load(this);
    // 初始化 ReactiveUI
    RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
}
public override void OnFrameworkInitializationCompleted()
{
    ConfigureServices();
    if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    {
        // Line below is needed to remove Avalonia data validation.
        // Without this line you will get duplicate validations from both Avalonia and CT
        BindingPlugins.DataValidators.RemoveAt(0);
        desktop.MainWindow = _serviceProvider.GetRequiredService<MainWindow>();
    }
    base.OnFrameworkInitializationCompleted();
}
private void ConfigureServices()
{
    var services = new ServiceCollection();
    // 注册 MessageBus 为 Singleton
    services.AddSingleton(MessageBus.Current);
    // 注册 ViewModel 为 Transient
    services.AddTransient<MainWindowViewModel>();
    services.AddTransient<AnotherViewModel>();
    // 注册 MainWindow
    services.AddTransient<MainWindow>();
    _serviceProvider = services.BuildServiceProvider();
} 
- MainWindow.axaml中实例化AnotherViewModel,初始化是为了创建订阅信息监听
 
// 实例化 AnotherViewModel
_anotherViewModel = serviceProvider.GetRequiredService<AnotherViewModel>(); 
- 添加Send Message按钮测试;
 
<Button Content="Send Message" Command="{Binding SendTestMessageCommand}" />
public partial class MainWindowViewModel : ViewModelBase
{
    private readonly IMessageBus _messageBus;
    public ReactiveCommand<Unit, Unit> SendTestMessageCommand { get; }
    public MainWindowViewModel(IMessageBus messageBus)
    {
        _messageBus = messageBus;
        SendTestMessageCommand = ReactiveCommand.Create(SendTestMessage);
    }
    public void SendTestMessage()
    {
        var message = new TestMessage { Content = "Hello from MainViewModel" };
        _messageBus.SendMessage(message);
    }
} 
4、在AnotherViewModel中订阅消息
private readonly IMessageBus _messageBus;
public AnotherViewModel(IMessageBus messageBus)
{
    _messageBus = messageBus;
    // 订阅消息
    _messageBus.Listen<TestMessage>()
        //.ObserveOn(RxApp.MainThreadScheduler)
        .Subscribe(Observer.Create<TestMessage>(HandleMessage));
}
private void HandleMessage(TestMessage message)
{
    // 处理接收到的消息
    Debug.WriteLine($"Message received in AnotherViewModel: {message.Content}");
    // 如果需要更新 UI,确保在主线程上执行
    Dispatcher.UIThread.InvokeAsync(() =>
    {
        // 这里可以执行 UI 更新操作
    });
} 
5、运行测试结果

深潜
如果不使用ReactiveUI的MessageBus,还有什么什么实现方式?
1、通过构造函数注入,如果组件层级深,此方法会使代码耦合性极大增加,建议不超过3级;
2、使用ReactiveUI中ReactiveObject,使用RaiseAndSetIfChanged(),变化后通知;
3、使用ReactiveUI中的ReactiveList<T>处理集合变化,监听change和ItemChange事件;
4、使用.Net中的ObservableCollection<T>配合ReactiveUI的this.WhenAnyValue().BindTo().Subscrble().DisposeWith()使用,个人理解等同于ReactiveList<T>。
总结:
- 使用MessageBus可解耦,省去中间传参处理参数环节且在ReactiveUI中开箱即用,较推荐使用。
 - 对于非ReativeUI的MVVM项目可以使用.Net中的ObservableCollection<T>;
 - 层级简单较容易实现的,根据实际情况出发,非必要引入消息总线。
 - 关于Avalonia+ReactiveUI开发,是在使用中探索,加之网上开发相关资料并不丰富,特此分享,欢迎指正!!!
 
本文完。



















