WinRT metro app по-прежнему блокирует поток пользовательского интерфейса при вызове с помощью асинхронного метода
У меня есть простое приложение metro, содержащее кнопку, ярлык и выпадающий список. Выпадающий список содержит список файлов, из которых я могу читать. Когда я нажимаю на кнопку, содержимое выбранного файла считывается в метку. Файлы находятся в папке Documents (то есть в известных папках WinRT.Документы из библиотеки). Каждый файл представляет собой файл хранилища в WinRT API.
Метод чтения файла является асинхронным методом (использует async / await). Чтобы доказать асинхронное поведение, я сделал метод чтения файлов как длительный процесс. Поэтому, выполняя этот длительный метод, я должен иметь возможность свободно щелкнуть по выпадающему списку и выбрать другой файл. Это происходит потому, что поток пользовательского интерфейса не должен блокироваться при чтении файла. Однако в настоящее время этого не происходит. Он по-прежнему, кажется, блокирует поток пользовательского интерфейса, и выпадающий список замораживается во время выполнения метода long running. Должно быть, я делаю здесь что-то странное. Не могли бы вы сказать мне, пожалуйста, почему пользовательский интерфейс не отзывчивый? Мой пример кода приведен ниже.
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; 
      }                
  }
}
1 ответ:
Если вы выполняете такой код в потоке пользовательского интерфейса:
var whatever = await DoSomethingAsync(); // some more codeЗатем
// some more codeтакже будет выполняться в потоке пользовательского интерфейса. И это именно твоя проблема. После чтения файла выполняется длинный цикл в потоке пользовательского интерфейса, поэтому пользовательский интерфейс зависает.Если вы хотите смоделировать какую-то длительную операцию, вы можете сделать это несколькими способами:
Выполните цикл в фоновом потоке с помощью
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; }
Не тратьте время процессора и используйте
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; }