如何根据另一个属性的选择异步更新ViewModel属性

3
假设我在视图中有某种列表控件,我从中选择一个名称并将其设置为视图模型中的“SelectedName”属性。当选择名称时,我想异步获取与该名称相关联的一组数据,并使用该数据设置另一个属性,然后更新绑定到该其他数据属性的视图中的另一个控件。
无法在属性中使用async/await,因此无法在“SelectedName”setter中进行请求和赋值。
在这种情况下,MVVM最佳实践是什么?
我认为,可能选择名称也会触发视图模型中的命令(RelayAsyncCommand)执行异步获取和分配工作。但是,在命令执行之前是否有任何保证“SelectedName”会被更新,以便命令需要使用它?
2个回答

4
与任何异步UI一样,您需要考虑的第一件事情是额外状态将会是什么样子。具体来说,现在您有一个“正在加载”状态,并且现在也是思考“错误”状态的好时机。
我开发了一种类型,在我的异步数据绑定MSDN文章中进行了描述,它类似于可绑定的Task<T>。使用该类型,您可以执行以下操作:
public string SelectedName
{
  get { return _selectedName; }
  set
  {
    _selectedName = value;
    OnPropertyChanged();
    SelectedNameDetails = new NotifyTaskCompletion<SelectedNameData>(FetchNameDataAsync());
  }
}

public NotifyTaskCompletion<SelectedNameData> SelectedNameDetails
{
  get { return _selectedNameDetails; }
  set { _selectedNameDetails = value; OnPropertyChanged(); }
}

接下来,您可以使用 SelectedNameDetails.Result 进行数据绑定以在加载时显示详细信息;使用 SelectedNameDetails.IsNotCompletedSelectedNameDetails.IsSuccessfullyCompletedSelectedNameDetails.IsFaulted 来在“正在加载”、“成功”和“错误”视图状态之间切换。


1
是的!上周末我读了你的文章,然后就忘记了。关于始终记得处理所有相关状态的观点非常好。 - Coding Dude
你好,@Stephen Cleary,我看到了你的文章并一直在尝试跟进。当我使用Onpropertychanged时,它会抛出一个不存在的错误。我正在尝试在具有NotifyTaskCompleted的属性加载数据后更新另一个属性。目前遇到了一些困难。 - gdubs
@gdubs:很难确定问题出在哪里。你能否发布你自己的问题,包括示例代码? - Stephen Cleary
@Stephen Cleary 抱歉回复晚了,刚找到时间。这是大致的情况。我不再收到错误信息了,但我仍然无法弄清楚如何在数据从 API 调用返回后正确更新另一个变量。这是一个 fiddle https://dotnetfiddle.net/OWoTq2(无法运行,但只显示我正在进行的调用)。 - gdubs
@gdubs 在任务完成之前,您无法访问 NotifyTask<T>.Result;在此期间,它为 null。对于您来说,最简单的解决方案可能是创建一个单独的 async 方法,等待 NotifyTask<T>.Task 然后设置 Clients - Stephen Cleary
显示剩余2条评论

0

虽然你不能直接在SelectedName的setter中执行异步操作,但你仍然可以在setter内部调用一个执行所有异步逻辑并设置第二个属性的async void方法。唯一的缺点是这个方法无法在完成时通知SelectedName的setter(因为它必须是void),但在你的情况下应该不需要这样做吧?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接