问题
I have successfully built a plugin mechanism where I can create UI controls in a separate AppDomain and display them as part of a Form in the main AppDomain.
These UI controls do their own data loading so when I open a form about 10 different plugins get created and each needs to load its data.
Again this all works fine if I do it synchronously but I would like to use the async/await pattern in each plugin. My refresh method looks like this:
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
OnDataChanged(); <= Worker Thread :(
}
Now here starts the problem. When I enter this method I am on the main UI thread. But when the await is over I am on a worker thread so I get a cross thread exception in the OnDataChanged()
method which updates the controls.
await
should by default use the SynchronizationContext.Current
for its continuation but since I am in an other AppDomain this happens to be NULL.
So my question is. How can I configure await to continue on the current thread, that is the UI thread?
I know I can grab a control and do Invoke() but I am also using the MVVM pattern and this is in the View Model so I don't have access to any controls there and all View Model -> View communications are done through data bindings.
回答1:
I finally figured out how to get back to the UI-Thread from within a separate AppDomain, without having a handle to a control.
Since my view model is always instantiated on the UI thread, I simply grab the current dispatcher:
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher
Now in my RefreshData method all I have to do is dispatch the action I want to perform after the await.
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
_dispatcher.Invoke(() => OnDataChanged()); <= UI Thread :)
}
This can of course be made more fancy, by encapsulating the dispatcher, etc.
The idea for this actually came from the: MVVM Light Toolkit
来源:https://stackoverflow.com/questions/36627061/no-synchronizationcontext-when-calling-await-in-a-another-appdomain