Как вызвать асинхронный метод из PropertyChanged? - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть приложение WPF на основе архитектуры MVVM.Я реализую общий и широко используемый интерфейс INotifyPropertyChanged в моих ViewModels, потому что мне нужно реагировать на взаимодействие с пользователем.

Но как мне выполнить асинхронное действие (например, загрузку некоторых данных) из синхронного PropertyChangedобработчик событий без с использованием async void 'хаков'?

Заранее спасибо!

РЕДАКТИРОВАТЬ

Основная причина, почемумне нужно избегать async void, потому что я работаю в тестовой среде.Асинхронные пустые методы не тестируются: (

Ответы [ 3 ]

0 голосов
/ 15 февраля 2019

На самом деле это не примерно async void.

Обычно вы хотите запустить асинхронную операцию и позволить вашему установщику свойств вернуться.Пример фрагмента:

private string carManufacturerFilter;

public string СarManufacturerFilter
{
    get { return carManufacturerFilter; }
    set
    {
        if (carManufacturerFilter != value)
        {
            carManufacturerFilter = value;
            OnPropertyChanged();

            // fire async operation and forget about it here;
            // you don't need it to complete right now;
            var _ = RefreshCarsListAsync();
        }
    }
}

private async Task RefreshCarsListAsync()
{
    // call some data service
    var cars = await someDataService.GetCarsAsync(carManufacturerFilter)
        .ConfigureAwait(false);

    // ...
}

Обратите внимание, что здесь есть много вещей, которые можно добавить:

  • , так как это подход «забыл и забыл», вам нужно заблокировать ввод пользователяпока операция не запущена.Другими словами, должен быть какой-то индикатор занятости:
  • вы можете отложить запуск асинхронной операции.Это обычно применимо, когда есть строковые свойства.Вы не хотите запускать асинхронную операцию после каждого введенного пользователем символа.Вместо этого желательно подождать, пока пользователь завершит ввод;
  • может быть несколько свойств, которые запускают одну и ту же асинхронную операцию (представьте сложный фильтр данных).Некоторые из них должны запускать операцию немедленно (например, флажок), некоторые требуют задержки перед запуском;
  • вам нужно обрабатывать исключения внутри асинхронного метода и как-то отображать ошибки.

PS IНастоятельно рекомендуем взглянуть на Реактивный интерфейс .

0 голосов
/ 15 февраля 2019

Причина, по которой поддерживается async void, заключается в том, что она позволяет использовать await в обработчиках событий, которые обычно являются недействительными.Если вы хотите, чтобы он был тестируемым, напишите весь код в другом методе async Task и попросите обработчик событий вызвать его напрямую.Протестируйте этот метод в своих тестах.

void OnPropertyChanged(PropertyChangedEventArgs e)
{
    OnPropertyChangedAsync(e)
}

// Test this method
async Task OnPropertyChangedAsync(PropertyChangedEventArgs e)
{
    ...
}
0 голосов
/ 15 февраля 2019

Вы не можете.INotifyPropertyChanged не поддерживает асинхронные вызовы.Вам нужно взломать или переосмыслить свою стратегию.

INotifyPropertyChanged не предназначен для асинхронных действий.Его цель - позволить классу уведомить пользовательский интерфейс об изменении данных.Пользовательский интерфейс работает в выделенном потоке, поэтому следует избегать операций с несколькими потоками.

Вы должны использовать "ужасный" подход async void.

Вы также можете использовать Dispatcher.BeingInvoke (async () => { … await …} ), ноэто будет так же, как при использовании async void.

...