把 async 关键字用于 UWP 应用程序,需要注意,在 UI 线程中调用 await 之后,当异步方法返回时,将默认返回到 UI 线程中。这便于在异步方法完成后更新 UI 元素。
注意
为了创建 UWP 应用程序,需要 Windows 10,Windows 系统必须在 “开发人员模式” 下配置。启用 “开发人员模式” 时,需要打开 Windows 设置,选择 Update & Security 磁贴,选择 For developers 类别,并单击单选按钮 Developermode。这样系统就可以运行旁路的应用程序了(未从 Windows Store 中安装的应用程序),并为 “开发人员模式” 添加一个 Windows 包。
为了理解功能和问题,创建一个通用 Windows 应用程序。这个应用程序包含 5个 按钮和一个TextBlock元素,来演示不同的场景:
<StackPanel><Button Content="Start Async" Click="OnStartAsync" Margin="4" /><Button Content="Start Async with Config" Click="OnStartAsyncConfigureAwait"Margin="4" /><Button Content="start Async with thread switch"Click="OnStartAsyncWithThreadSwitch" Margin="4" /><Button Content="Use IAsyncOperation" Click="OnIAsyncOperation" Margin="4" /><Button Content="Deadlock" Click="OnStartDeadlock" Margin="4" /><TextBlock x:Name="text1" Margin="4" />
</StackPanel>
在 OnStartAsync 方法中,UI 线程的线程 ID 写入 TextBlock 元素。接下来调用异步方法 Task.Delay,它不阻塞 UI 线程,在此方法完成后,线程 ID 将再次写入TextBlock:
private async void OnstartAsync(object sender, RoutedEventArgs e)
{text1.Text = $"UI thread: {GetThread()}";await Task.Delay(1000);text1.Text += $"in after await: {GetThread()}";
}
为了访问线程 ID,可以使用 Environment 类。在 UWP 应用程序中,Thread 类是无效的 —— 至少在构建版本 15063 之前是这样的:
private string GetThread() => $"thread: {Environment.CurrentManagedThreadId)";
运行应用程序时,可以在文本元素中看到类似的输出。与控制台应用程序相反,UWP 应用程序定义了一个同步上下文,在等待之后,可以看到与以前相同的线程。这允许直接访问 UI 元素:
UI thread: thread 3
after await:thread 3