CaliburnMicro IEventAggregator在子视图中无法工作的问题排查
CaliburnMicro EventAggregator子视图触发NullReferenceException问题解决
问题概述
我是CaliburnMicro新手,目前在使用IEventAggregator实现视图间参数共享时遇到问题:在.NET6环境下,新窗口模式可以正常通过EventAggregator传递数据,但将新窗口改为ShellView内嵌的子视图(WPF UserControl)后,调用子视图的SendBack方法时,_eventAggregator.PublishOnUIThreadAsync(ToSend)触发System.NullReferenceException异常。
相关代码
1. Bootstrapper代码
public class Bootstrapper : BootstrapperBase { private SimpleContainer _container; public Bootstrapper() { Initialize(); } protected override void Configure() { _container = new SimpleContainer(); _container.Singleton<IWindowManager, WindowManager>(); _container.Singleton<IEventAggregator, EventAggregator>(); _container.PerRequest<ShellViewModel>(); } protected override object GetInstance(Type service, string key) { var instance = _container.GetInstance(service, key); if (instance != null) return instance; throw new InvalidOperationException("Could not locate any instances."); } protected override IEnumerable<object> GetAllInstances(Type service) { return _container.GetAllInstances(service); } protected override void BuildUp(object instance) { _container.BuildUp(instance); } protected override void OnStartup(object sender, StartupEventArgs e) { DisplayRootViewFor<ShellViewModel>(); } }
注:_container.Singleton<IWindowManager, WindowManager>()已无需使用,暂未注释用于排查。
2. 消息类EventMessage
public class EventMessage { public string Text { get; set; } }
3. 子视图模型SecondWindowViewModel
class SecondWindowViewModel : Screen { private readonly IEventAggregator _eventAggregator; private string _secondTextBox; public string SecondTextBox { get { return _secondTextBox; } set { _secondTextBox = value; NotifyOfPropertyChange(() => SecondTextBox); } } public SecondWindowViewModel(IEventAggregator eventAggregator) { this._eventAggregator= eventAggregator; } public void SendBack() { EventMessage ToSend = new EventMessage(); ToSend.Text = SecondTextBox; _eventAggregator.PublishOnUIThreadAsync(ToSend); } }
4. ShellViewModel代码
public class ShellViewModel : Conductor<Object>, IHandle<EventMessage> { private readonly IEventAggregator _eventAggregator; private string _parentText; public string ParentText { get { return _parentText; } set { _parentText = value; NotifyOfPropertyChange(() => ParentText); } } public ShellViewModel(IEventAggregator eventAggregator) { ActivateItemAsync(new SecondWindowViewModel(_eventAggregator)); _eventAggregator = eventAggregator; _eventAggregator.Subscribe(this); } public Task HandleAsync(EventMessage message, CancellationToken cancellationToken) { ParentText = message.Text; return Task.CompletedTask; } //public void NewWindow() //{ //WindowManager wm = new WindowManager(); //SecondWindowViewModel swm = new SecondWindowViewModel(_eventAggregator); //wm.ShowWindowAsync(swm); //} }
注:CaliburnMicro新版本中仅HandleAsync方法有效,已在ShellView中添加<ContentControl x:Name="ActiveItem"/>。
问题分析
- 构造函数执行顺序错误:ShellViewModel构造函数中,先调用
ActivateItemAsync(new SecondWindowViewModel(_eventAggregator)),此时_eventAggregator字段尚未被赋值(赋值语句在后面),导致传递给SecondWindowViewModel的是null,最终子视图中的_eventAggregator为空,调用Publish方法时触发空引用异常。 - 子视图模型访问修饰符问题:SecondWindowViewModel未添加
public修饰符,导致CaliburnMicro容器无法自动解析该类型(若后续改用容器注入会失败)。
解决方案
方案1:调整构造函数代码顺序
修正ShellViewModel构造函数的执行顺序,先给_eventAggregator字段赋值,再创建子视图模型:
public ShellViewModel(IEventAggregator eventAggregator) { _eventAggregator = eventAggregator; // 优先赋值字段 _eventAggregator.Subscribe(this); ActivateItemAsync(new SecondWindowViewModel(_eventAggregator)); // 传递已初始化的实例 }
方案2:使用容器自动注入子视图模型(更规范)
- 在Bootstrapper的Configure方法中注册SecondWindowViewModel:
protected override void Configure() { _container = new SimpleContainer(); _container.Singleton<IWindowManager, WindowManager>(); _container.Singleton<IEventAggregator, EventAggregator>(); _container.PerRequest<ShellViewModel>(); _container.PerRequest<SecondWindowViewModel>(); // 注册子视图模型 }
- 修改SecondWindowViewModel为public:
public class SecondWindowViewModel : Screen // 添加public修饰符 { // ... 原有代码不变 }
- 在ShellViewModel中通过容器获取子视图模型实例:
public ShellViewModel(IEventAggregator eventAggregator, SimpleContainer container) { _eventAggregator = eventAggregator; _eventAggregator.Subscribe(this); var secondVm = container.GetInstance<SecondWindowViewModel>(); ActivateItemAsync(secondVm); }
此方法依赖容器自动注入IEventAggregator,避免手动实例化时的参数传递错误。
补充说明
- CaliburnMicro 4.x及以上版本要求事件处理实现
IHandleAsync<T>接口的HandleAsync方法,旧版Handle方法已不再生效,符合你遇到的情况。 - 确保所有需要容器解析的视图模型都使用
public访问修饰符,否则容器无法创建实例。
内容的提问来源于stack exchange,提问作者David Benavent Tornero
相关产品推荐
相关产品推荐

