使用MVVM模式实现异步"loadData"方法的最佳方法

Ser*_*694 11 c# wpf mvvm windows-runtime windows-phone-8.1

我试图了解在调用更新我的ViewModel的异步方法时使用的最佳方法是什么.现在,让我说我有这样的事情:

视图:

private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    //Call my ViewModel method to update the data the UI is bound to          
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

public async Task loadData()
{
    this.Source = await loadStuffFromDatabaseAsync();
}
Run Code Online (Sandbox Code Playgroud)

现在,我不确定应该使用以下哪种方法:

1)在我的LoadState方法中,使用:

await Task.Run(async () => { await ViewMode.loadData(); });
Run Code Online (Sandbox Code Playgroud)

2)使用Task.Run而不等待Action内的loadData方法:

await Task.Run(() => { ViewModel.loadData(); });
Run Code Online (Sandbox Code Playgroud)

3)调用我的loadData方法:

await ViewModel.loadData().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

4)调用loadData方法而不在我的View类中等待它,并在我的loadData方法中使用Task.Run:

视图:

private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    ViewModel.loadData();  
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

public async void loadData()
{
    await Task.Run(async () => 
    {
        this.Source = await loadStuffFromDatabaseAsync();
    });
}
Run Code Online (Sandbox Code Playgroud)

这些协议之间的主要区别是什么?

一个比另一个更高效,我应该特别选择一个吗?

谢谢你的帮助!:)

塞尔吉奥

Ste*_*ary 3

Task.Run仅当您需要将 CPU 密集型工作或阻塞工作移出 UI 线程时才应使用。这里的情况并非如此,因此直接调用(选项 3)是最自然的。

依次来看:

await Task.Run(async () => { await ViewMode.loadData(); });
Run Code Online (Sandbox Code Playgroud)

该选项将loadData在线程池线程上执行。这可能效果不太好,因为loadData正在更新 UI(通过设置 VM 属性间接更新)。即使它确实有效(即,某些 MVVM 框架可以在某些情况下正确处理来自后台线程的更新),它也可能是不必要的,因为它loadData是一种异步方法。

此外,它async无缘无故地增加了状态机开销。

await Task.Run(() => { ViewModel.loadData(); });
Run Code Online (Sandbox Code Playgroud)

此选项具有所有相同的问题,但它的效率稍高一些,因为它没有async状态机开销。但它仍在后台线程上更新虚拟机属性并不必要地使用后台线程。

public async void loadData()
Run Code Online (Sandbox Code Playgroud)

这是最糟糕的。它继承了其他线程的相同问题:在后台线程上更新 VM 属性并使用不必要的后台线程。除此之外,它还增加了 的问题async void。一个问题是NavigationHelper_LoadState无法捕获任何异常loadData。另一个问题是loadData不容易测试。

所以使用简单的方法,直接调用即可:

await ViewModel.loadData().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)