Calling Dispatcher.Invoke () on the dispatcher thread

I'm having a problem displaying a WPF window using Window.Show:

Fixing System.InvalidOperationException was unhandled Message: An unhandled exception of type "System.InvalidOperationException" occurred in WindowsBase.dll Additional information: The calling thread cannot access this object because it owns another thread.

Fair enough - the standard way to fix this is to use Dispatcher.Invoke to make sure the window is displayed on the dispatcher thread.

The weird thing is, as far as I can tell, the code is already running on the Dispatcher thread.

This code throws an exception:

if (Dispatcher.CurrentDispatcher.Thread != Thread.CurrentThread || 
        Application.Current.Dispatcher.Thread != Thread.CurrentThread)
{
    throw new ApplicationException("Current thread is not Dispatcher");
}

window.Show(); // throws InvalidOperationException

      

This code works fine:

if (Dispatcher.CurrentDispatcher.Thread != Thread.CurrentThread || 
        Application.Current.Dispatcher.Thread != Thread.CurrentThread)
{
    throw new ApplicationException("Current thread is not Dispatcher");
}

Dispatcher.CurrentDispatcher.Invoke(window.Show);

      

As I understand it, if the current thread is the dispatcher thread, then calling Dispatcher.Invoke should be equivalent to calling the method directly. Clearly this is wrong, but can anyone explain why?

To complicate matters, this code is in a method that is called via COM from a VB6 application (yes, I know). What effects can it have?

+3


source to share


1 answer


I suspect the problem here is the wrong .NET sync context (or lack thereof) in the first case.

As I understand it, this code is being called from an unmanaged host, which naturally doesn't have a .NET sync context set on the main UI thread.

Try this in the first case:

System.Diagnostics.Debug.WriteLine(new { System.Threading.SynchronizationContext.Current });
window.Show(); // throws InvalidOperationException

      



I expect what you see { Current = null }

in the debug output.

For the second case, do the following:

Dispatcher.CurrentDispatcher.Invoke(() => {
    System.Diagnostics.Debug.WriteLine(new { System.Threading.SynchronizationContext.Current });
    window.Show();
});

      

This should output { Current = System.Windows.Threading.DispatcherSynchronizationContext }

.

+2


source







All Articles