如果不需要访问 UI 元素,就可以配置 await,以避免使用同步上下文。下面的代码片段演示了配置,并说明为什么不应该从后台线程上访问 UI 元素。.
使用 OnStartAsyncConfigureAwait 方法,在将 UI 线程的 ID 写入文本输入后,将调用本地函数 AsyncFunction。在这个本地函数中,启动线程是在调用异步方法 Task.Delay 之前写入的。使用此方法返回的任务,将调用 ConfigureAwait。在这个方法中,任务的配置是通过传递设置为 false 的 continueOnCapturedContext 参数来完成的。通过这种上下文配置,会发现等待之后的线程不再是 UI 线程。使用不同的线程将结果写入 result 变量即可。如 try 块所示,千万不要从非 UI 线程中访问 UI 元素。得到的异常包含 HRESULT 值,如 when 子句所示。只有这个异常在 catch 中捕获:结果返回给调用者。对于调用方,也调用了 ConfigureAwait,但是这次,continueOnCapturedContext 设置为 true。在这里,在等待之前和之后,方法都在 UI 线程中运行:
private async void OnStartAsyncConfigureAwait(object sender, RoutedEventArgs e)
{
text1.Text = $"UI thread: {GetThread()}";
string s = await AsyncFunction().ConfigureAwait(
continueOnCapturedContext: true);
// after await, with continueOnCapturedContext true we are back in the UI thread
text1.Text += $"\n{s}\nafter await: {GetThread()}";
async Task<string> AsyncFunction()
{
string result = $"\nasync function: {GetThread()}\n";
await Task.Delay(1000). ConfigureAwait(continueOnCapturedContext: false);
result += $"\nasync function after await : {GetThread()}";
try
{
text1.Text = "this is a call from the wrong thread";
return "not reached";
}
catch (Exception ex) when (ex.HResult == -2147417842)
{
return result;
// we know it's the wrong thread
// don't access UI elements from the previous try block
}
}
}
UI thread: thread 3
async function: thread 3
async function after await: thread 6
after await: thread 3