Prism 4.1升级至6后ThreadOption.UIThread订阅触发异常问题
这个坑我升级Prism的时候也踩过!Prism 6对EventAggregator的线程上下文校验比4.1严格多了——当你用ThreadOption.UIThread订阅事件时,它要求EventAggregator实例本身必须是在UI线程上构造的,否则就会抛出那个InvalidOperationException。而你提到涉事类是DI容器解析的,大概率是因为你的EventAggregator是在非UI线程被DI首次创建的。
下面给你几个靠谱的解决方法:
1. 提前在UI线程手动解析EventAggregator
DI容器默认是单例模式管理EventAggregator的,所以只要在UI线程提前触发一次解析,后续注入的就都是这个UI线程构造的实例了。最简单的做法是在App的启动逻辑里加一行:
protected override void InitializeShell() { // 手动解析一次,强制EventAggregator在UI线程构造 Container.Resolve<IEventAggregator>(); base.InitializeShell(); }
这样后续所有通过DI注入的IEventAggregator都会是这个绑定了UI线程上下文的实例,再用ThreadOption.UIThread订阅就不会报错了。
2. 检查DI容器的初始化线程
如果你的DI容器(或者部分服务)是在后台线程初始化的,那一定要把依赖EventAggregator的服务解析逻辑移到UI线程。比如用WPF的Dispatcher调度:
Application.Current.Dispatcher.Invoke(() => { // 在这里解析那些用到EventAggregator的服务 var myBusinessService = Container.Resolve<IMyBusinessService>(); });
确保EventAggregator的首次实例化发生在UI线程,这是最根本的解决思路。
3. 临时替代:手动切换线程(不推荐)
如果实在没法调整初始化线程,也可以放弃ThreadOption.UIThread,在事件处理方法里手动切到UI线程。不过这只是权宜之计,毕竟违背了Prism事件聚合器的设计初衷:
// 订阅时用默认的PublisherThread选项 _eventAggregator.GetEvent<MyCustomEvent>().Subscribe(HandleEvent); private void HandleEvent(MyEventPayload payload) { // 手动调度到UI线程处理逻辑 Application.Current.Dispatcher.Invoke(() => { // 你的UI更新逻辑写在这里 MyTextBox.Text = payload.Message; }); }
总结一下:Prism 6的EventAggregator需要绑定UI线程的SynchronizationContext才能支持UIThread订阅,所以核心就是确保它的实例在UI线程创建——提前手动解析或者调整DI初始化线程是最优解。
内容的提问来源于stack exchange,提问作者Andrew Stephens

