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 3

1 ответ:

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

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

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

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

  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; 
     }
    
  2. Не тратьте время процессора и используйте 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; 
     }