如何从PropertyChanged调用异步方法?

时间:2019-02-15 13:04:04

标签: c# wpf mvvm async-await inotifypropertychanged

我有一个基于MVVM架构的WPF应用程序。我正在ViewModels上实现通用且广泛使用的INotifyPropertyChanged接口,因为我需要对用户交互做出反应。

但是如何使用async void'hacks'从同步的PropertyChanged事件处理程序执行异步操作(例如,加载一些数据)?

谢谢!

编辑

我需要避免使用async void的主要原因是因为我在测试驱动的环境中工作。异步void方法不可测试:(

3 个答案:

答案 0 :(得分:2)

支持async void的原因是允许在事件处理程序中使用await,这些事件处理程序通常是无效的。 如果您希望它是可测试的,请用另一个async Task方法编写整个代码,然后让事件处理程序直接调用它。在测试中测试此方法。

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

// Test this method
async Task OnPropertyChangedAsync(PropertyChangedEventArgs e)
{
    ...
}

答案 1 :(得分:1)

实际上,这与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);

    // ...
}

请注意,这里有很多要添加的内容:

  • 由于这是一劳永逸的方法,因此您需要阻止用户输入,直到操作运行为止。换句话说,应该有某种忙碌指示器;
  • 您可能要延迟异步操作触发。当存在字符串属性时,通常适用。您不想在用户键入每个字符之后触发异步操作。相反,最好等待用户完成输入;
  • 可能有多个属性,它们引发相同的异步操作(想象复杂的数据过滤器)。其中一些应立即触发操作(例如复选框),其中一些需要延迟才能触发;
  • 您需要处理异步方法内的异常并以某种方式显示错误。

P.S。我强烈建议您看看Reactive UI

答案 2 :(得分:0)

不能。 INotifyPropertyChanged不支持异步调用。您需要进行修改或重新考虑策略。

INotifyPropertyChanged不适用于异步操作。其目标是使类能够通知UI其数据已更改。 UI在专用线程中工作,因此必须避免跨线程操作。

您应该使用“可怕的” async void方法。

您也可以使用Dispatcher.BeingInvoke (async () => { … await …} ),但与使用async void相同。