Select Page

Multi-threaded applications appear to be more and more the norm with the latest version of Windows development.  In fact, it’s become a necessity when displaying additional windows with a UWP app.  With this article, I want to capture the resolution to a problem that caused research with very thin answers.

So, I have code like this:

await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId, ViewSizePreference.UseHalf);

That call opens a whole new window in addition to the window that the app is already running.  Let’s refer to the app as (A) and the new window as (B).  Both (A) and (B) now have a UI thread.  However, I have my Services and Models sitting in (A) and an additional View and ViewModel pairing in (B).  So, when a make a change in my Model, the Model broadcasts a PropertyChanged notification.  Normally, the ViewModel catches it and so forth.

However, in this particular scenario, the Model and ViewModel are in different UI threads.  Thus, when PropertyChanged is called between, I could get a number of Exceptions:

Exception thrown: 'System.Runtime.InteropServices.COMException' in Common.dll
Additional information: A COM call to an ASTA was blocked because the call chain originated 
in or passed through another ASTA. This call pattern is deadlock-prone and disallowed by apartment
call control.

Or:

Exception thrown: 'System.InvalidCastException' in Common.dll Additional information: Unable to 
cast COM object of type 'System.ComponentModel.PropertyChangedEventHandler' to class type
'System.ComponentModel.PropertyChangedEventHandler'. Instances of types that represent COM
components cannot be cast to types that do not represent COM components; however they can be cast
to interfaces as long as the underlying COM component supports QueryInterface calls for the IID
of the interface.

So these Exceptions can be fairly aggravating.  After a bunch of research, trial & error, and even pair programming, the solution turned out to be something like this:

First, I have a base class that implements INPC.  I call it ObservableObject, but others might call it BindableBase.  Both my Models and ViewModels derives from it.  In the Constructor, I save off the SynchronizationContext (arguably, might get away with the Dispatcher, since they are in the same ballpark).  Looks like this:

protected ObservableObject()
{
   _context = SynchronizationContext.Current;
}
SynchronizationContext _context = null;

Then, when I want to raise the PropertyChanged event, I do something like this:

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
   PropertyChangedEventHandler eventHandler = this.PropertyChanged;
   if (eventHandler != null)
   {
      if (SynchronizationContext.Current == null && _context != null)
      {
         _context.Post(_ => { eventHandler(this, new PropertyChangedEventArgs(propertyName)); }, null);
      }
      else
      {
         eventHandler(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

With that, I can pass data between the two distinct Windows.

I really want to call out that there is very little information on how to deal with multiple windows.  Here are some links to sites that did not completely help, but were possibly in the right ballpark:

That list contains a bit more than SynchronizationContext.  What drove the research was trying to implement a Projection feature.  This led to communicating with an Aggregator, then to a few more topics about multiple Windows.  And when talking about multiple Windows, there’s no way to avoid multi-threading.

On a side note, I’m disappointed in Microsoft for lack of useful support.  In many cases, I find that the question/answer format on blogs is best practiced on a site like Stack Overflow.  But for Windows products, I expect Microsoft to have considerably more useful information than Stack Overflow.  Instead, I came across the Exception that I was having eventually and saw this completely useless question/answer posted:

Projection binding, InvalidCastException on property changed

Don’t get me wrong, I appreciate people’s efforts.  But I look at the answer of “the 2nd Window is indeed a different UI thread and you need to take that into account in your design/code.” and wonder if Microsoft Techs must meet some sort of quota when answering questions.  Quality in answers at these official outlets is expected.