Метро-приложение WinRT по-прежнему блокирует поток пользовательского интерфейса при вызове с помощью асинхронного метода.

У меня есть простое метро-приложение, содержащее кнопку, метку и выпадающий список. Выпадающий список содержит список файлов, из которых я могу читать. Когда я нажимаю на кнопку, содержимое выбранного файла считывается в метку. Файлы находятся в папке «Документы» (т. е. KnownFolders.DocumentsLibrary WinRT). Каждый файл представляет StorageFile в WinRT API.

Метод чтения файлов является асинхронным методом (использует async/await). Чтобы доказать асинхронное поведение, я сделал метод чтения файла длительным процессом. Следовательно, при выполнении этого длительного метода я должен иметь возможность свободно щелкнуть раскрывающийся список и выбрать другой файл. Это связано с тем, что поток пользовательского интерфейса не должен блокироваться при чтении файла. Однако в настоящее время этого не происходит. Кажется, что он по-прежнему блокирует поток пользовательского интерфейса, и выпадающий список зависает, пока выполняется длительный метод. Должно быть, я делаю что-то странное здесь. Скажите, пожалуйста, почему интерфейс не отвечает? Мой пример кода ниже.

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; 
      }                
  }

}


person Spock    schedule 03.04.2012    source источник
comment
Ну, святая корова, сколько файлов в этом каталоге?   -  person Hans Passant    schedule 04.04.2012
comment
@HansPassant всего несколько, но мне любопытна причина вашего вопроса?   -  person Spock    schedule 04.04.2012


Ответы (1)


Если вы выполняете подобный код в потоке пользовательского интерфейса:

var whatever = await DoSomethingAsync();
// some more code

Затем // some more code также будет выполняться в потоке пользовательского интерфейса. В чем именно ваша проблема. После того, как файл прочитан, вы выполняете длинный цикл в потоке пользовательского интерфейса, поэтому пользовательский интерфейс зависает.

Если вы хотите смоделировать какую-то длительную операцию, вы можете сделать это несколькими способами:

  1. Выполните цикл в фоновом потоке, используя Task.Run()< /a> и асинхронно дождитесь его завершения:

    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; 
     }
    
  2. Не тратьте время ЦП и используйте Task.Delay()< /a> для задержки выполнения кода:

    private async Task<string> ReadFileAsync(IStorageFile storageFile)
    {
        var fileContent = await FileIO.ReadTextAsync(storageFile)
                                      .ConfigureAwait(false);
    
        await Task.Delay(TimeSpan.FromSeconds(10));
    
        return fileContent; 
     }
    
person svick    schedule 03.04.2012
comment
Это казалось очевидным ответом, но я не знал, как объяснить тот факт, что содержащий метод также awaited. - person Ritch Melton; 04.04.2012
comment
@RitchMelton, это ничего не меняет. Как вы думаете, почему? - person svick; 04.04.2012
comment
Невежество. Я предположил, что метод await, отмеченный async, имеет все содержимое как асинхронное, поскольку он возвращает задачу. - person Ritch Melton; 04.04.2012
comment
Что ж, его содержимое является асинхронным, поскольку нет ни одного потока, синхронно ожидающего FileIO.ReadTextAsync(). Но если он начинается в потоке пользовательского интерфейса, он также продолжается там по умолчанию. - person svick; 04.04.2012
comment
Хорошо, это имеет смысл. Я бы предложил (1), но тогда я угадал. Спасибо за информацию. - person Ritch Melton; 04.04.2012