问题
Im trying to update some UWP UI from a background thread via the Dispatcher. However, the handler passwed to the RunAsync method is still getting executed on a backlground thread.
I have no idea how to fix this - have I missed something?
--EDIT--
I only have one window, which is Window.Current
I have tried the Community Toolkit DispatcherHelper class, but I'm still getting the exact same exception
private static async void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var panel = (SidePanelInfo) d;
var x = e.NewValue as TaskItemViewModel;
await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
panel.DescriptionBox.Document.SetText(TextSetOptions.FormatRtf, x?.Description ?? "");
});
}
回答1:
If you are already on the background thread, you cannot access Window.Current.Dispatcher
as the background thread has no Window.Current
set (the property gets the Window
instance associated with the UI thread it is called from).
Instead you should first retrieve the Dispatcher
instance while on the UI thread and then use this instance to execute RunAsync
.
However - OnSelectedItemChanged
rather seems like a UI event handler in which case you should not require running code on UI thread. Check if the UnauthorizedAccessException
does not happen if you just run panel.DescriptionBox.Document.SetText
with the same parameters when triggered from a Button
click for example.
Multi-view and multi-window apps
The problem can occur in case you are creating a multi-view or multi-window UWP app, because in UWP each window has its own UI thread. This means that when you want to update properties across windows, you always need to use the Dispatcher
of the target window/app view.
回答2:
DispatcherHelper from the WindowsCommunityToolkit can be very helpful here.
it gives you option to execute code on UI thread or execute code on MainView ( if you have multiple windows )
DispatcherHelper.ExecuteOnUIThreadAsync<T>(() =>
{
// Code to execute on main window's UI thread
});
await CoreApplication.MainView.Dispatcher.AwaitableRunAsync<T>( () =>
{
});
回答3:
OK, I have finally found out what was going on, and it was not what I was expecting.
The issue had nothing to do with threading or dispatchers, despite the dispatcher executing on a worker thread (UWP dispatchers dont seem to run on the Main Thread like WPF it seems), and despite the error being the same error as you would expect if you had a cross-threading UI exception.
It turns out that I had a RichEditBox that was inadvertently in read-only mode. And because this control doesn't support binding to its content, I was setting the content in code-behind. The exception was because I was setting the text of the control while it was in read-only mode.
It's a shame that the control couldn't have given a more meaningful error, or been editable programmatically even if in read-only mode - like the WPF equivalent. But there you go. Hopfully this Q&A page will help someone else having the same problems.
A big thanks to Martin Zikmund for attempting to help me when I was sure it was a dispatching issue.
来源:https://stackoverflow.com/questions/52373127/uwp-how-can-dispatcher-dispatchedhandler-run-on-worker-thread