MVVMHelpers AsyncCommand await работает некорректно

#c# #.net #xamarin.forms #async-await

#c# #.net #xamarin.forms #async-await

Вопрос:

Я внедряю Xamarin.Формирует приложение, используя Nuget MVVMHelpers: https://github.com/jamesmontemagno/mvvm-helpers

Я пытаюсь использовать команду AsyncCommand из этой библиотеки, которая описана в этом блоге: https://johnthiriet.com/mvvm-going-async-with-async-command

Я хочу, чтобы была реализована следующая цепочка:

  1. Пользователь нажимает на кнопку загрузки
  2. Откроется диалоговое окно загрузки, и пользователь выберет файл
  3. Текст файла запрашивается на richTextEdit

Чтобы справиться с этим, я использую следующую ViewModel:

     public class UploadViewModel : BaseViewModel
{
    private string[] _allowedFileTypes;
    private string _fileText;
    private bool _hasFile;

    public AsyncCommand UploadFileCommand { get; private set; }

    public string FileText { get { return _fileText; } set { SetProperty(ref _fileText, value); } }

    public bool HasFile { get { return _hasFile; } set { SetProperty(ref _hasFile, value); } }

    public UploadViewModel()
    {
        Title = "Upload";
        _allowedFileTypes = new string[] { "txt" };
        UploadFileCommand = new AsyncCommand(UploadFileAsync, x => IsNotBusy);
    }

    private async Task UploadFileAsync()
    {
        if (IsBusy)
            return;            

        try
        {
            IsBusy = true;
            var fileData = await CrossFilePicker.Current.PickFile(_allowedFileTypes);

            if (fileData == null)
                return;

            StreamReader reader = new StreamReader(fileData.GetStream());
            FileText = await reader.ReadToEndAsync();
            HasFile = !string.IsNullOrWhiteSpace(FileText);
        }
        finally
        {
            IsBusy = false;
        }
    }
}
 

Обратите внимание, что BaseViewModel взят из MVVMHelpers

Моя проблема в том, что в асинхронном методе UploadFileAsync isBusy = false достигается до завершения работы. Поэтому я думаю, что это проблема моего понимания async / await. Я прочитал несколько блогов и ответов на Stackoverflow, но не понял. Также пытался запустить GetStream() в собственной задаче, но с тем же результатом.

ОБНОВЛЕНИЕ: представление в Xamarin.Forms XAML выглядит следующим образом:

 <?xml version="1.0" encoding="utf-8" ?>
 
 <ContentPage.BindingContext>
    <viewModels:UploadViewModel />
</ContentPage.BindingContext>

<ContentPage.Content>
    <StackLayout>
        <button:SfButton Text="Upload File" Command="{Binding UploadFileCommand}" IsVisible="{Binding IsNotBusy}" Margin="5,5,5,5"/>
        <richTextEditor:SfRichTextEditor IsVisible="{Binding HasFile}" Text="{Binding FileText}" ReadOnly="True" VerticalOptions="FillAndExpand" ShowToolbar="False"/>
        <busyindicator:SfBusyIndicator x:Name="busyindicator" IsBusy="{Binding IsBusy}" AnimationType="DoubleCircle"/>
    </StackLayout>
</ContentPage.Content>
 

Комментарии:

1. Я хотел вам помочь и привел здесь минимально воспроизводимый пример. Первоначально я смог смоделировать вашу проблему, однако в какой-то момент это прекратилось, к сожалению, я не могу вспомнить, что я сделал. Может быть, вы можете его использовать?

2. Привет, @Leander, спасибо за пример. Вы используете асинхронные методы, не ожидая их и не возвращая задачу. Насколько я знаю, это плохая практика. Я думаю, что в вашем случае все работает синхронно, и именно поэтому оно работает. В моем случае я использую анимацию загрузки в пользовательском интерфейсе, которая зависнет, если мой код будет выполняться без await .

3. Вы уверены, что опубликованный код воспроизводит проблему?

4. Привет @StephenCleary я добавил макет представления. Это точно воспроизводит проблему. Я использую компоненты syncfusion, но вы должны быть в состоянии заменить это простой кнопкой.

5. @Sebi Хотя я был убежден, что мой код уже был асинхронным, я немного изменил его, и теперь PollBusy он определенно больше не синхронный. Снова finally выполняется после try блока. Может быть, вы также можете опубликовать MVCE?