从WPF视图模型中的属性设置器调用异步方法是错误的吗?

时间:2018-05-04 13:06:43

标签: c# wpf task-parallel-library

当属性更改其值时,我想调用从Web服务获取数据的异步方法,然后更新UI绑定到的另一个属性,从而导致UI更新。我觉得更新是异步的,因为我希望UI在更新过程中保持响应。

从非异步设置器调用异步方法是错误的吗?我注意到如果异步方法返回void,那么VS不会抱怨,但如果它返回Task,那么visual studio会抱怨没有等待调用。我的代码如下所示:

public int Property1
{
    set 
    {
        _property1 = value;
        NotityPropertyChanged();
        UpdateData();
    }
}

private async void UpdateData()
{
    // show data loading message
    var data = await GetDataFromWebService();
    Property2 = data;
    // hide data loading message
}

它似乎有效,但我想知道如果返回类型为Task,如果我从VS获得警告,我是否按照预期的方式使用async。

更新:一些答案和评论建议用户使用命令而不是更新以响应属性的更改。对于我的情况,我不确定如何应用,所以提供有关UI如何工作的更多细节。

在用户界面中,有日期选择器(绑定到视图模型上有问题的属性),用户选择要查看记录的日期。当用户选择新日期时,应用程序应显示忙碌指示符,然后在后台获取记录以避免阻止UI线程。我希望在选择日期时启动更新,而无需用户在选择日期后按下按钮。

将日期选择器的SelectionChanged事件绑定到ViewModel上的async命令或者为SelectionChanged直接调用视图模型上的update方法会更好吗?

3 个答案:

答案 0 :(得分:4)

  

从非异步设置器调用异步方法是错误的吗?

简而言之,是的。属性不应该在其setter中启动异步后台操作。

我建议你阅读Stephen Cleary的博文和MSDN关于这个主题的文章:

异步编程:异步MVVM应用程序的模式:数据绑定: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx

异步OOP 3:属性: https://blog.stephencleary.com/2013/01/async-oop-3-properties.html

您可能还想查看功能性MVVM框架,例如ReactiveUI,它通过将属性转换为您可以订阅的可观察值的流来处理此方案:https://reactiveui.net/docs/getting-started/

答案 1 :(得分:-1)

这不是已经说过的“最干净”的方式,但你可以离开它。它首先没有害处,除非你在快速任务背后隐藏了一个意想不到的长而昂贵的操作。

MSDN says

  

异步方法也可以具有void返回类型。此返回类型主要用于定义事件处理程序,其中需要void返回类型。异步事件处理程序通常用作异步程序的起点。

     

无法等待具有void返回类型的异步方法,并且   void返回方法的调用者无法捕获任何异常   方法抛出。

一个简单的解决方案可能是收听PropertyChanged事件。这更像是逃避制定者的工作。更好的方法是通过向其添加异步执行来实现ICommand接口asynchrounous,从而使ViewModel公开更新命令。然后,只要属性发生更改,您就可以从View中调用此AsyncCommand。您还可以将新值作为命令参数传递给ViewModel。

答案 2 :(得分:-1)

仅在属性发生变化时自动调用更新通常是一个坏主意 通常,按钮和命令是更好的计划。 您也可以从UI调用命令而不是使用该setter。这样做相对简单。

至少,您需要一个不同的线程来以某种方式调用某些Web服务 火与遗忘的线程并不是很糟糕 只要你不在乎你忘记它后发生的事情就会发生什么。