MVVM XAML 应用程序中的异步等待
Async await in MVVM XAML Applications
我试图了解我应该如何在具有 async/await 模式的 ViewModel 中接收初始数据。我们看代码:
public interface IPeopleService
{
Task<IEnumerable<Person> GetPeopleAsync();
}
public MainViewModel
{
public ObservableCollection<Person> People{get;set;}
public MainViewModel(IPeopleService peopleService)
{
LoadMyData(peopleService);
}
public async Task LoadMyData(IPeopleService peopleService)
{
try
{
People = await peopleService.GetPeopleAsync();
}
catch(Exception e)
{
//log
//notify user
}
}
}
有一个 PeopleService,其中包含人员数据的异步方法。它注入了 IOC(无论如何)。之后我调用异步操作 LoadMyData(以防止阻塞 UI,因此没有 await 关键字)并在该方法中我从服务中调用异步操作以捕获所有异常并通知用户。这种方法有什么问题?
我阅读了来自 msdn 的文章:https://msdn.microsoft.com/en-us/magazine/dn605875.aspx,当我注意到为这种任务创建一个通用 class 并更改我的所有属性以使用该 class 作为通用参数时,更改 XAML 绑定以接收 Property.Result 属性,我认为这很疯狂,并且在项目中造成了很大的混乱。此外,ViewModel 中的属性指定此 属性 是异步的,在我看来这是糟糕的设计。解决我的问题的最简单方法是什么?我的解决方案可以让一切变得简单吗?
After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. What's wrong with this approach?
您的 UI 在加载数据时未被阻止。那挺好的。但是异步数据加载带来了一些问题: UI 在数据加载时显示什么? UI 如何向用户显示错误?
在您当前的代码中,UI 列表在加载数据时是空的。 IMO 至少应该有一种 "loading" 状态,以便用户可以区分空结果集和仍在进行中的操作。另外,我假设您的 notify user
代码是通过代码而不是通过数据绑定调出一个对话框或其他东西。 IMO 错误指示器比模态对话框更好。
NotifyTaskCompletion<T>
背后的目的是它充当数据可绑定的异步操作。所以你可以使用它的属性来改变 to/from 到 "loading" 和 "error" 状态。这就是您的绑定必须更改为 .Result
的原因 - 因为您要绑定到异步操作的 result。如果您不想显示 "loading" 指示器并且不想通过数据绑定显示错误,那么是的,NotifyTaskCompletion<T>
就太过分了。
这取决于您想要进行数据绑定的程度。如果您对所有内容都在代码中感到满意,那很好:
public async Task LoadMyData(IPeopleService peopleService)
{
try
{
... // Hide people display
... // Show loading indicator
People = await peopleService.GetPeopleAsync();
... // Show people display
}
catch(Exception e)
{
... // Show error indicator
}
finally
{
... // Hide loading indicator
}
}
或者,您可以使用数据绑定来完成这一切,这会使您的代码更简单:
// (wrapped in NotifyTaskCompletion)
public async Task LoadMyData(IPeopleService peopleService)
{
People = await peopleService.GetPeopleAsync();
}
两种方法我都做过,但如果我有一个执行大量异步操作的项目,我倾向于 NotifyTaskCompletion<T>
。
我试图了解我应该如何在具有 async/await 模式的 ViewModel 中接收初始数据。我们看代码:
public interface IPeopleService
{
Task<IEnumerable<Person> GetPeopleAsync();
}
public MainViewModel
{
public ObservableCollection<Person> People{get;set;}
public MainViewModel(IPeopleService peopleService)
{
LoadMyData(peopleService);
}
public async Task LoadMyData(IPeopleService peopleService)
{
try
{
People = await peopleService.GetPeopleAsync();
}
catch(Exception e)
{
//log
//notify user
}
}
}
有一个 PeopleService,其中包含人员数据的异步方法。它注入了 IOC(无论如何)。之后我调用异步操作 LoadMyData(以防止阻塞 UI,因此没有 await 关键字)并在该方法中我从服务中调用异步操作以捕获所有异常并通知用户。这种方法有什么问题?
我阅读了来自 msdn 的文章:https://msdn.microsoft.com/en-us/magazine/dn605875.aspx,当我注意到为这种任务创建一个通用 class 并更改我的所有属性以使用该 class 作为通用参数时,更改 XAML 绑定以接收 Property.Result 属性,我认为这很疯狂,并且在项目中造成了很大的混乱。此外,ViewModel 中的属性指定此 属性 是异步的,在我看来这是糟糕的设计。解决我的问题的最简单方法是什么?我的解决方案可以让一切变得简单吗?
After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. What's wrong with this approach?
您的 UI 在加载数据时未被阻止。那挺好的。但是异步数据加载带来了一些问题: UI 在数据加载时显示什么? UI 如何向用户显示错误?
在您当前的代码中,UI 列表在加载数据时是空的。 IMO 至少应该有一种 "loading" 状态,以便用户可以区分空结果集和仍在进行中的操作。另外,我假设您的 notify user
代码是通过代码而不是通过数据绑定调出一个对话框或其他东西。 IMO 错误指示器比模态对话框更好。
NotifyTaskCompletion<T>
背后的目的是它充当数据可绑定的异步操作。所以你可以使用它的属性来改变 to/from 到 "loading" 和 "error" 状态。这就是您的绑定必须更改为 .Result
的原因 - 因为您要绑定到异步操作的 result。如果您不想显示 "loading" 指示器并且不想通过数据绑定显示错误,那么是的,NotifyTaskCompletion<T>
就太过分了。
这取决于您想要进行数据绑定的程度。如果您对所有内容都在代码中感到满意,那很好:
public async Task LoadMyData(IPeopleService peopleService)
{
try
{
... // Hide people display
... // Show loading indicator
People = await peopleService.GetPeopleAsync();
... // Show people display
}
catch(Exception e)
{
... // Show error indicator
}
finally
{
... // Hide loading indicator
}
}
或者,您可以使用数据绑定来完成这一切,这会使您的代码更简单:
// (wrapped in NotifyTaskCompletion)
public async Task LoadMyData(IPeopleService peopleService)
{
People = await peopleService.GetPeopleAsync();
}
两种方法我都做过,但如果我有一个执行大量异步操作的项目,我倾向于 NotifyTaskCompletion<T>
。