gpt4 book ai didi

mvvm - 从数据绑定(bind)属性 setter 中调用异步方法的正确方法?

转载 作者:行者123 更新时间:2023-12-03 11:43:10 26 4
gpt4 key购买 nike

现在我知道属性不支持异步/等待是有充分理由的。但有时您需要从属性 setter 启动一些额外的后台处理 - 一个很好的例子是 MVVM 场景中的数据绑定(bind)。

在我的例子中,我有一个绑定(bind)到 ListView 的 SelectedItem 的属性。当然,我立即将新值设置为支持字段,属性的主要工作就完成了。但是 UI 中选中项的变化还需要触发 REST 服务调用,以根据现在选中的项获取一些新数据。

所以我需要调用一个异步方法。显然,我不能等待它,但我也不想触发并忘记调用,因为我可能会在异步处理期间错过异常。

现在我的看法如下:

private Feed selectedFeed;
public Feed SelectedFeed
{
get
{
return this.selectedFeed;
}
set
{
if (this.selectedFeed != value)
{
this.selectedFeed = value;
RaisePropertyChanged();

Task task = GetFeedArticles(value.Id);

task.ContinueWith(t =>
{
if (t.Status != TaskStatus.RanToCompletion)
{
MessengerInstance.Send<string>("Error description", "DisplayErrorNotification");
}
});
}
}
}

好的,除了我可以将处理从 setter 移到同步方法之外,这是处理这种情况的正确方法吗?有没有我看不到的更好、更简洁的解决方案?

很想看到其他一些关于这个问题的看法。我有点好奇我找不到关于这个具体主题的任何其他讨论,因为在大量使用数据绑定(bind)的 MVVM 应用程序中对我来说似乎很常见。

最佳答案

我有一个 NotifyTaskCompletion type in my AsyncEx library本质上是 INotifyPropertyChanged Task 的包装/Task<T> . AFAIK 目前在 async 上可用的信息非常少。结合 MVVM,所以如果你找到任何其他方法,请告诉我。

无论如何,NotifyTaskCompletion如果您的任务返回结果,则该方法最有效。即,从您当前的代码示例来看,它看起来像 GetFeedArticles将数据绑定(bind)属性设置为副作用,而不是返回文章。如果您返回 Task<T>相反,您可以得到如下代码:

private Feed selectedFeed;
public Feed SelectedFeed
{
get
{
return this.selectedFeed;
}
set
{
if (this.selectedFeed == value)
return;
this.selectedFeed = value;
RaisePropertyChanged();
Articles = NotifyTaskCompletion.Create(GetFeedArticlesAsync(value.Id));
}
}

private INotifyTaskCompletion<List<Article>> articles;
public INotifyTaskCompletion<List<Article>> Articles
{
get { return this.articles; }
set
{
if (this.articles == value)
return;
this.articles = value;
RaisePropertyChanged();
}
}

private async Task<List<Article>> GetFeedArticlesAsync(int id)
{
...
}

然后你的数据绑定(bind)可以使用 Articles.Result获取结果集合(在 null 完成之前为 GetFeedArticlesAsync)。您可以使用 NotifyTaskCompletion “开箱即用”也可以将数据绑定(bind)到错误(例如 Articles.ErrorMessage ),并且它具有一些 bool 便利属性( IsSuccessfullyCompletedIsFaulted )来处理可见性切换。

请注意,这将正确处理无序完成的操作。由于 Articles实际上代表异步操作本身(而不是直接的结果),它会在新操作开始时立即更新。因此,您永远不会看到过时的结果。

您不必使用数据绑定(bind)来处理错误。你可以通过修改 GetFeedArticlesAsync 来制作你想要的任何语义。 ;例如,通过将异常传递给您的 MessengerInstance 来处理异常。 :

private async Task<List<Article>> GetFeedArticlesAsync(int id)
{
try
{
...
}
catch (Exception ex)
{
MessengerInstance.Send<string>("Error description", "DisplayErrorNotification");
return null;
}
}

同样,没有内置自动取消的概念,但同样很容易添加到 GetFeedArticlesAsync :

private CancellationTokenSource getFeedArticlesCts;
private async Task<List<Article>> GetFeedArticlesAsync(int id)
{
if (getFeedArticlesCts != null)
getFeedArticlesCts.Cancel();
using (getFeedArticlesCts = new CancellationTokenSource())
{
...
}
}

这是当前开发的一个领域,所以请做改进或 API 建议!

关于mvvm - 从数据绑定(bind)属性 setter 中调用异步方法的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20951610/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com