UWP SolidColorBrush - The application called an interface that was marshalled for a different thread exception

2

I have a UWP application that receives a dynamic updates via SignalR. I'm using Template10 and the SignalR listener is located in the ViewModel class.

When messages are received by SignalR - the Model is updated. The block of code that updates the model is wrapped in Despatcher method:

VM - method invoked by SignalR:

private async void AddOrder(WorkOrder order)
    {
        await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            order.Lines = new ObservableCollection<WorkOrderLine>(order.Lines.OrderByDescending(m => m.QtyScanned < m.Qty);
            this.Orders.Add(order);
        });
    }

Then inside of the model class I have this code (there is another child observablecollection on WorkOrderLine class):

private void TrolleyAllocations_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged("WorkOrderLineItems");
            ForegroundColor = GetForegroundColour();
        }

The GetForegroundColor is the following:

private SolidColorBrush GetForegroundColour()
    {
        try
        {
            if (WorkOrderLineItems.Where(m => m.Status == UnitStatus.Other).Any())
            {
                return new SolidColorBrush(Colors.Red);
            }
            else if (WorkOrderLineItems.Where(m => m.Status == UnitStatus.AssemblyLine).Any())
            {
                return new SolidColorBrush(Colors.Green);
            }
            else if (WorkOrderLineItems.Where(m => m.Status == UnitStatus.PreLoad).Any())
            {
                return new SolidColorBrush(Colors.Black);
            }
            else if (WorkOrderLineItems.Where(m => m.Status == UnitStatus.FullAndComplete).Any())
            {
                return new SolidColorBrush(Colors.LightGray);
            }

            return new SolidColorBrush(Colors.Black);
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"Exception in foreground colour: {ex.Message} {ex.StackTrace}");
            return null;
        }
    }

Now, on any new SolidColorBrush() the wollowing exception is thrown:

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Prior to the recent changes I was using the Conveter in x:Bind to do the work that GetForegroundColor method is doing (I have decided to change the approach due to the performance hit converters incur) - and it was working just fine. I'm also updating some of the other databound properties - which update UI (code omitted) and this works just fine.

Any ideas would eb greatly appreciated. It's been driving me insane.

c#
multithreading
xaml
uwp

1 Answer

6

You need to run your model's changes on the main thread. I've got the same problem in UWP using MVVM.

I think you need to wrap with a dispatcher your event's handler code in order to run it on the UI thread.

private void TrolleyAllocations_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
      Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
      {
           RaisePropertyChanged("WorkOrderLineItems");
           ForegroundColor = GetForegroundColour();
      }
}

Now your handler is called and fired from a background task, so GetForegroundColor() is on the same thread.

answered on Stack Overflow Jul 13, 2017 by Marco

User contributions licensed under CC BY-SA 3.0