当通过异步方法调用时,WinRT metro应用程序仍然会阻塞UI线程
本文关键字:线程 UI 应用程序 metro 异步方法 调用 WinRT | 更新日期: 2023-09-27 18:29:58
我有一个简单的metro应用程序,它包含一个按钮、一个标签和一个下拉列表。下拉列表包含我可以从中读取的文件列表。当我点击按钮时,所选文件的内容会被读取到标签中。文件位于Documents文件夹(即WinRT的KnownFolders.DocumentsLibrary)中。每个文件表示WinRT API中的StorageFile。
文件读取方法是一种异步方法(使用async/await)。为了证明异步行为,我将文件读取方法作为一个长时间运行的过程。因此,在执行这种长时间运行的方法时,我应该能够自由地单击下拉列表并选择不同的文件。这是因为UI线程在读取文件时不应该被阻止。然而,目前还没有出现这种情况。它似乎仍然阻塞了UI线程,并且在长时间运行的方法出现时,下拉列表被冻结。我一定是在这里做什么奇怪的事。你能告诉我为什么UI没有响应吗?我的代码示例如下。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FileAccess
{
public sealed partial class MainPage : Page
{
private readonly StorageFolder storageFolder;
public MainPage()
{
this.InitializeComponent();
storageFolder = KnownFolders.DocumentsLibrary;
AddFiles();
}
private async void AddFiles() //Add files to the drop down list
{
var filesList = await storageFolder.GetFilesAsync();
IEnumerable<FileItem> fileItems
= filesList.Select(x => new FileItem(x.Name, x.Name));
cboSelectFile.ItemsSource = fileItems;
cboSelectFile.SelectedIndex = 0;
}
private async void BtnReadFile_Click(object sender, RoutedEventArgs e)
{
IStorageFile storageFile = await storageFolder.GetFileAsync((string)cboSelectFile.SelectedValue);
if (storageFile != null)
{
LblReadFile.Text = await ReadFileAsync(storageFile); //long running method**************
}
}
private async Task<string> ReadFileAsync(IStorageFile storageFile) //long running method**************
{
var fileContent = await FileIO.ReadTextAsync(storageFile);
for (Int64 i = 0; i < 10000000000; i++)
{
}
return fileContent;
}
}
}
如果在UI线程上执行这样的代码:
var whatever = await DoSomethingAsync();
// some more code
然后// some more code
也将在UI线程上执行。这正是你的问题。读取文件后,在UI线程上执行长循环,这就是UI冻结的原因。
如果你想模拟一些长时间运行的操作,你可以用几种方法:
使用
Task.Run()
在后台线程上执行循环,并异步等待它完成:private async Task<string> ReadFileAsync(IStorageFile storageFile) { var fileContent = await FileIO.ReadTextAsync(storageFile); await Task.Run(() => { for (Int64 i = 0; i < 10000000000; i++) {} }); return fileContent; }
不要浪费CPU时间,使用
Task.Delay()
延迟代码的执行:private async Task<string> ReadFileAsync(IStorageFile storageFile) { var fileContent = await FileIO.ReadTextAsync(storageFile) .ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(10)); return fileContent; }