Avalonia 中窗口间通信不依赖全局静态变量或紧耦合设计,推荐使用事件总线(Event Aggregator)、依赖注入服务、或回调委托等松耦合方式。核心原则是避免直接引用对方窗口实例,保证可测试性和生命周期安全。
使用 EventAggregator 实现发布-订阅通信
这是最推荐的跨窗口通信方式,尤其适合一对多、解耦场景。Avalonia 本身不内置 EventAggregator,但可轻松集成 CommunityToolkit.Mvvm 中的
WeakReferenceMessenger或第三方库如
Prism.Events(需适配)。 在发送方窗口(如 MainWindow)中发送消息: Messenger.Default.Send(new NavigationRequested("Settings"));在接收方窗口(如 SettingsWindow)中注册监听(建议在
OnAttachedToVisualTree或构造后): Messenger.Default.Register
this作为接收器可自动解注册,避免内存泄漏;消息类型建议定义为不可变 record 或 class。
通过共享的 ViewModel 或服务注入传递数据
若两个窗口共用同一业务上下文(如编辑同一个文档),可将状态托管在共享的 ViewModel 或 Service 中,并通过 DI 注入到各窗口。
定义一个生命周期为Singleton或
Transient(按需)的服务: public interface ISharedStateService { string CurrentText { get; set; } }在 App.axaml.cs 的 DI 容器中注册: builder.Services.AddSingleton
打开新窗口时传参 + 回调委托(适合模态/一次性交互)
适用于主窗口打开设置窗、弹窗确认等场景,强调“发起-响应”关系。
在主窗口中创建子窗口时传入 Action 或 Func 委托: var dialog = new SettingsDialog();dialog.OnSave = () => { RefreshUI(); };
dialog.Show(this);子窗口内部在保存后触发: OnSave?.Invoke();注意:确保委托不捕获窗口实例以防循环引用;关闭子窗口前可置空委托。
避免直接引用窗口实例通信
不要在窗口 A 中持有窗口 B 的字段引用(如
private SettingsWindow _settings;),这会导致生命周期混乱、内存泄漏和单元测试困难。即使使用
Window.GetWindow(this)查找父窗,也仅限临时 UI 层联动(如菜单定位),不可用于业务数据流转。
