4

I need to show a dialog box that is created with WPF from an MTA thread. I create a new thread, set it to be STA, and display the dialog there. But I cannot figure out from documentation if I actually need to call Dispatcher.Run() and then later shutdown the dispatcher before the thread terminates.

Thread thread = new Thread(() =>
{
    SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));

    dialog = new MyDialog();

    dialog.Closed += (sender, e) => Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);

    dialog.Show();

    Dispatcher.Run();
});

thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
thread.Join();

I have found that the behavior appears to be the same if I instead do the following.

Thread thread = new Thread(() =>
{
    dialog = new MyDialog();
    dialog.ShowDialog();
});

thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
thread.Join();

Do I actually need to setup the dispatcher, or does creating a WPF window and calling ShowDialog do that for me?

I noticed that the Window constructor calls Dispatcher.CurrentDispatcher, which will create a dispatcher if one does not exist. But I don't see any calls to Dispatcher.Run in the constructor or ShowDialog.

dbiel
  • 132
  • 5
  • 3
    Plenty of sharks in that water you're trying to swim. But no, ShowDialog() is not good enough, you must use Dispatcher.Run() so that essential WPF duties are taken care of. Use the window's Close event to call the dispatcher's InvokeShutdown() so the thread ends cleanly. – Hans Passant Apr 20 '17 at 21:57
  • 1
    There's not enough code in your question to provide a specific answer, but most likely you should just stop trying to call `ShowDialog()` anywhere except the main UI thread. Just use the correct `Dispatcher` object and call `Invoke()` or `InvokeAsync()` (as appropriate to your needs...from your attempt above, it looks like `Invoke()` will suffice). – Peter Duniho Apr 21 '17 at 06:11
  • What's the purpose of displaying the dialog window on another thread if you still block the main thread by calling Join()? – mm8 Apr 21 '17 at 09:21
  • The examples I have seen on MSDN and other places always show Dispatcher.Run() being called after dialog.Show(). Is there a reason for this? If I use ShowDialog, that will block and my dialog will already be closed or closing when Dispatcher.Run() is called if I followed that model. Can I call Run before ShowDialog? – dbiel Apr 21 '17 at 14:10
  • There is not a whole lot more relevant code, and I was trying to keep the post simple. The thread that calls this, is an MTA thread in a callback registered with code I don't have access to. I need a new thread because you can only show a dialog in an STA thread. Essentially, this is called as a plugin from another app, so I don't have access to the main UI thread (although I can request the main HWND). – dbiel Apr 21 '17 at 14:14

0 Answers0