Prism EventAggregator 异常 - 必须在 UI 线程上构建 [英] Prism EventAggregator Exception - must be constructed on the UI thread

查看:82
本文介绍了Prism EventAggregator 异常 - 必须在 UI 线程上构建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚重新访问了一些非常旧的代码,将其更新到最新版本的 Prism(版本 5),在模块初始化期间,我收到以下异常消息:

Exception is: InvalidOperationException - 要使用 UIThread 选项进行订阅,必须在 UI 线程上构造 EventAggregator.

无论我在哪里执行以下操作:

eventAggregator.GetEvent().Subscribe(OnAppStatusChanged, ThreadOption.UIThread, true);

将所有这些实例更改为:

eventAggregator.GetEvent().Subscribe(OnAppStatusChanged);

显然解决了问题,应用程序正常运行.

您如何确保 Unity 在 UI 线程上构建 EventAggregator?

更新

我现在已将以下代码添加到解决方案中以尝试解决此问题:

protected override void ConfigureContainer(){Container.RegisterType();var eventAggregator = new EventAggregator();Container.RegisterInstance(typeof(IEventAggregator), eventAggregator);base.ConfigureContainer();}

所以这是在我的 Bootstrapper 的 UI 线程上显式创建 EventAggregator 并且我仍然看到关于 ThreadOption.UIThread 抛出相同的异常.>

StockTraderRI 示例项目也使用了 ThreadOption.UIThread 并且在处理 IEventAggregator 时似乎没有做任何明确的事情但它使用的是 MEF 而不是 Unity.

我已经阅读了新的 Prism 第 5 版文档,我在其中找到的有关这些更改的所有声明如下:

<块引用>

EventAggregator 现在必须在 UI 线程上构造才能正确获取对 UI 线程的 SynchronizationContext 的引用.

我在上面详述的代码更改中尝试过.

我的 Bootstrapper 看起来与我能找到的所有参考实现相同:

////<摘要>///初始化外壳.///</总结>protected override void InitializeShell(){base.InitializeShell();Application.Current.MainWindow = (Shell)Shell;Application.Current.MainWindow.Show();}///<summary>创建外壳.</summary>///<returns>主应用程序shell</returns>受保护的覆盖 DependencyObject CreateShell(){返回 ServiceLocator.Current.GetInstance();}

我还尝试在调用 ConfigureContainer 后立即手动解析 EventAggregator,如下所示:

/// 配置容器.protected override void ConfigureContainer(){base.ConfigureContainer();var ea = Container.Resolve();}

当查看 ea 上的 syncContext 属性时,它是 null,尽管它看起来是 EventAggregator已在 UI 线程上解决.而且我仍然看到这个异常.

有没有人看到这个问题并找出导致这个问题的原因?

我完全被难住了.

另一个更新

所以我只是检查了这是在哪个线程上创建的.我从 EventAggregator 派生了一个空类,并在 ctor 上放置了一个断点,构建该类的线程是 Main Thread ...

所以现在我更加困惑了.

解决方案

原来答案很简单.

在我的旧代码中,有一个看起来像这样的应用程序类是可以的(如果不理想的话):

公共部分类App{公共应用程序(){var bootstrapper = new MyBootStrapper();bootstrapper.Run();}}

Prism 5 不再适用于这种初始化.您需要像这样初始化应用程序:

public partial class App : Application{protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var bootStrapper = new MyBootStrapper();bootStrapper.Run();}}

I've just revisited some very old code to update it to the latest version of Prism (Version 5) and during Module initialisation I was getting the following exception message:

Exception is: InvalidOperationException - To use the UIThread option for subscribing, the EventAggregator must be constructed on the UI thread.

Wherever I was executing something like:

eventAggregator.GetEvent<AppStatusMessageEvent>()
.Subscribe(OnAppStatusChanged, ThreadOption.UIThread, true);

Changing all of these instances to:

eventAggregator.GetEvent<AppStatusMessageEvent>()
.Subscribe(OnAppStatusChanged);

Obviously fixes the issue and the app runs as normal.

How do you ensure that Unity constructs the EventAggregator on the UI Thread?

UPDATE

I have now added the following code to the solution in an attempt to fix this:

protected override void ConfigureContainer()
{
    Container.RegisterType<IShellView, Shell>();

    var eventAggregator = new EventAggregator();
    Container.RegisterInstance(typeof(IEventAggregator), eventAggregator);

    base.ConfigureContainer();
}

So this is explicitly creating the EventAggregator on the UI thread in my Bootstrapper and I'm still seeing the same exception being thrown about the ThreadOption.UIThread.

The StockTraderRI example project also makes use of the ThreadOption.UIThread and doesn't appear to do anything explicit when dealing with the IEventAggregator but it is using MEF not Unity.

I've been through the new Prism version 5 documentation and all I can find in there about these changes is a statement that says:

EventAggregator now must be constructed on the UI thread to properly acquire a reference to the UI thread’s SynchronizationContext.

Which I have tried in the code changes detailed above.

My Bootstrapper looks identical to all the reference implementations I can find:

/// <summary>
/// Initializes the shell.
/// </summary>
protected override void InitializeShell()
{
    base.InitializeShell();

    Application.Current.MainWindow = (Shell)Shell;
    Application.Current.MainWindow.Show();
}

/// <summary>Creates the shell.</summary>
/// <returns>The main application shell</returns>
protected override DependencyObject CreateShell()
{
    return ServiceLocator.Current.GetInstance<Shell>();
}

I've also tried to manually resolve the EventAggregator immediate after the call to ConfigureContainer like this:

/// <summary>Configures the container.</summary>
protected override void ConfigureContainer()
{
    base.ConfigureContainer();
    var ea = Container.Resolve<IEventAggregator>();
}

When looking at the syncContext property on the ea is it null despite that appears to be the EventAggregator having been resolved on the UI thread. And I'm still seeing this exception.

Has anyone seen this issue and worked out what is causing this problem?

I'm utterly stumped.

Another Update

So I just checked which thread this is being created on. I derived an empty class from EventAggregator and put a breakpoint on the ctor and the thread building the class is the Main Thread ...

So now I'm even more confused.

解决方案

Turns out that the answer was fairly simple.

In my old code it was OK (if not ideal) to have an app class that looked this this:

public partial class App
{
    public App()
    {
        var bootstrapper = new MyBootStrapper();
        bootstrapper.Run();
    }
}

Prism 5 no longer works with this kind of initialization. You need to initialize the application like this:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var bootStrapper = new MyBootStrapper();
        bootStrapper.Run();
    }
}

这篇关于Prism EventAggregator 异常 - 必须在 UI 线程上构建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆