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

Prism异步场景下通过事件关闭Dialog时报跨线程访问对象异常

问题根因

你遇到的跨线程访问异常核心原因是:

  • ContinueWith默认会在线程池的后台线程执行后续逻辑,导致LoadingFinishedEvent的发布操作不在UI线程运行
  • 订阅事件时未指定调度线程,CloseDialog方法也在后台线程执行,而对话框属于UI元素,所有UI相关操作必须在UI线程执行,因此触发异常

解决方案

方案1:修改事件订阅的线程调度(最推荐)

Prism的PubSubEvent订阅时支持指定线程执行选项,直接要求事件回调在UI线程执行即可,修改LoadingDialogViewModel的构造函数:

public LoadingDialogViewModel(IEventAggregator eventAggregator)
{
    // 增加ThreadOption.UIThread参数,指定事件处理逻辑在UI线程运行
    eventAggregator.GetEvent<LoadingFinishedEvent>().Subscribe(close => CloseDialog(null), ThreadOption.UIThread);
}

方案2:优化异步逻辑,避免后台线程发布事件

你当前使用的ContinueWith写法冗余且容易吞掉任务异常,直接用await会自动切回原同步上下文(UI线程)执行后续代码,修改WarehouseViewModel代码:

private async void LoadData()
{
    await WarehouseListLoad();
    // await后默认回到UI线程,此处发布事件天然线程安全
    _eventAggregator.GetEvent<LoadingFinishedEvent>().Publish(true);
}

private async Task WarehouseListLoad()
{
    _dialogService.ShowDialog("LoadingDialogView");
    List<Warehouse> warehouses = await Task.Run(() =>
    {
        return _warehouseStore.GetAll();
    });
    // 此处可直接给绑定属性赋值,无需担心跨线程问题
}

兜底方案:手动调度UI线程执行关闭逻辑

如果场景特殊不确定执行线程,可以在RaiseRequestClose中主动调度到UI线程执行操作,WPF环境下写法如下:

public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
    if (Application.Current.Dispatcher.CheckAccess())
    {
        RequestClose?.Invoke(dialogResult);
    }
    else
    {
        Application.Current.Dispatcher.Invoke(() => RequestClose?.Invoke(dialogResult));
    }
}

以上方案任选其一即可解决问题,推荐方案1和方案2搭配使用,写法更规范也能避免后续其他异步UI问题。

内容的提问来源于stack exchange,提问作者horst

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 07:06:04