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))
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
});
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.
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).
User contributions licensed under CC BY-SA 3.0