2

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.

Jammer
  • 9,969
  • 11
  • 68
  • 115

1 Answers1

3

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();
    }
}
Jammer
  • 9,969
  • 11
  • 68
  • 115