You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"/>。

问题分析

  1. 构造函数执行顺序错误:ShellViewModel构造函数中,先调用ActivateItemAsync(new SecondWindowViewModel(_eventAggregator)),此时_eventAggregator字段尚未被赋值(赋值语句在后面),导致传递给SecondWindowViewModel的是null,最终子视图中的_eventAggregator为空,调用Publish方法时触发空引用异常。
  2. 子视图模型访问修饰符问题:SecondWindowViewModel未添加public修饰符,导致CaliburnMicro容器无法自动解析该类型(若后续改用容器注入会失败)。

解决方案

方案1:调整构造函数代码顺序

修正ShellViewModel构造函数的执行顺序,先给_eventAggregator字段赋值,再创建子视图模型:

public ShellViewModel(IEventAggregator eventAggregator)
{
    _eventAggregator = eventAggregator; // 优先赋值字段
    _eventAggregator.Subscribe(this);
    ActivateItemAsync(new SecondWindowViewModel(_eventAggregator)); // 传递已初始化的实例
}

方案2:使用容器自动注入子视图模型(更规范)

  1. 在Bootstrapper的Configure方法中注册SecondWindowViewModel:
protected override void Configure()
{
    _container = new SimpleContainer();
    _container.Singleton<IWindowManager, WindowManager>();
    _container.Singleton<IEventAggregator, EventAggregator>();
    _container.PerRequest<ShellViewModel>();
    _container.PerRequest<SecondWindowViewModel>(); // 注册子视图模型
}
  1. 修改SecondWindowViewModel为public:
public class SecondWindowViewModel : Screen // 添加public修饰符
{
    // ... 原有代码不变
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:39:35