当通过异步方法调用时,WinRT metro app仍会阻止UI线程

Spo*_*ock 3 c# asynchronous c#-5.0 async-ctp windows-runtime

我有一个简单的metro应用程序包含一个按钮,一个标签和一个下拉列表.下拉列表包含我可以读取的文件列表.当我单击按钮时,所选文件的内容将被读入标签.文件位于Documents文件夹中(即WinRT的KnownFolders.DocumentsLibrary).每个文件代表WinRT API中的StorageFile.

文件读取方法是一种异步方法(使用async/await).为了证明异步行为,我将文件读取方法作为一个长时间运行的过程.因此,在执行这个长时间运行的方法时,我应该能够自由地单击下拉列表并选择一个不同的文件.这是因为在读取文件时不应阻止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; 
      }                
  }
Run Code Online (Sandbox Code Playgroud)

}

svi*_*ick 7

如果在UI线程上执行这样的代码:

var whatever = await DoSomethingAsync();
// some more code
Run Code Online (Sandbox Code Playgroud)

然后// some more code也将在UI线程上执行.这正是你的问题.读取文件后,在UI线程上执行long循环,这就是UI冻结的原因.

如果要模拟一些长时间运行的操作,可以采用以下几种方式:

  1. 使用后台线程执行循环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; 
     }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 不要浪费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; 
     }
    
    Run Code Online (Sandbox Code Playgroud)