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