C# UWP The application called an interface that was marshalled for a different thread

6

I have a C# UWP app that contains a function I want to call every 5 seconds. The function runs fine when called from a button, and the Timer write to the debug console fine every 5 seconds....When I call the function from the Timer, all heck breaks loose. I get this:

System.Exception was unhandled by user code HResult=-2147417842 Message=The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

c#
multithreading
uwp
asked on Stack Overflow Dec 20, 2016 by Faust

3 Answers

12

I assume your function touches the app's UI. Anything which touches the UI needs to run on the UI's dispatcher thread (most apps will have only one until you get into multiple window apps).

You can use a Windows.UI.Xaml.DispatcherTimer to run your timer on the dispatcher thread.

If you need to run code on a worker thread and then touch UI on the dispatcher thread you can call Dispatcher.RunAsync to marshal a call back onto the dispatcher thread.

You can generally find your dispatcher from your Window via Window.Dispatcher.

var ignored = Window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
   // Do something on the dispatcher thread
});
answered on Stack Overflow Dec 20, 2016 by Rob Caplan - MSFT
1

Most likely you are using a Timer from System.Threading. That timer's events are not treated like a regular GUI event and if you are accessing a GUI item form the method invoked by that timer, it will cause issues since that thread is not the owner of the GUI item.

Use a Timer from System.Windows.Forms. That timer has access to your GUI items.

answered on Stack Overflow Dec 20, 2016 by CodingYoshi
0

You could actually use Observable.Interval from Reactive Extensions and specify explicitly on which dispatcher you want to observe timer events:

Observable.Interval(TimeSpan.FromSeconds(1), Scheduler.Default)
    .ObserveOn(coreWindow.Dispatcher)
    .Subscribe(_ => Log.Warning("Dispatcher.HasThreadAccess: " + coreWindow.Dispatcher.HasThreadAccess));

What I like about this approach is that you explicitly stating what happens on which thread (see SubscribeOn and ObserveOn).

answered on Stack Overflow Sep 11, 2018 by Stas Ivanov

User contributions licensed under CC BY-SA 3.0