Ber*_*nig 21 mvvm async-await windows-runtime winrt-async
现在我知道属性不支持异步/等待有充分理由.但有时您需要从属性设置器中启动一些额外的后台处理 - 一个很好的例子是MVVM场景中的数据绑定.
在我的例子中,我有一个绑定到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");
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
好的,除了事实上我可以将处理从setter转移到同步方法,这是处理这种情况的正确方法吗?有没有更好,更简洁的解决方案,我没有看到?
会非常有兴趣看到其他一些问题.我有点好奇,我无法找到关于这个具体主题的任何其他讨论,因为在MVVM应用程序中,大量使用数据绑定似乎很常见.
Ste*_*ary 12
NotifyTaskCompletion
我的AsyncEx库中有一个类型,它本质上是/ 的INotifyPropertyChanged
包装器.AFAIK目前与MVVM结合使用的信息非常少,所以如果您发现任何其他方法,请告诉我.Task
Task<T>
async
无论如何,NotifyTaskCompletion
如果您的任务返回结果,该方法最有效.即,从您当前的代码示例中看,它将GetFeedArticles
数据绑定属性设置为副作用,而不是返回文章.如果你做了这个返回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)
{
...
}
Run Code Online (Sandbox Code Playgroud)
然后您的数据绑定可用于Articles.Result
获取生成的集合(null
直到GetFeedArticlesAsync
完成).您可以使用NotifyTaskCompletion
"开箱即用"来将数据绑定到错误(例如Articles.ErrorMessage
),并且它具有一些布尔便利属性(IsSuccessfullyCompleted
,IsFaulted
)来处理可见性切换.
请注意,这将正确处理无序完成的操作.由于Articles
实际上表示异步操作本身(而不是直接结果),因此在启动新操作时会立即更新.所以你永远不会看到过时的结果.
你不具备使用数据错误处理结合.你可以修改GetFeedArticlesAsync
; 你可以做任何你想要的语义; 例如,通过将异常传递给您来处理异常MessengerInstance
:
private async Task<List<Article>> GetFeedArticlesAsync(int id)
{
try
{
...
}
catch (Exception ex)
{
MessengerInstance.Send<string>("Error description", "DisplayErrorNotification");
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
同样,没有内置自动取消的概念,但同样很容易添加到GetFeedArticlesAsync
:
private CancellationTokenSource getFeedArticlesCts;
private async Task<List<Article>> GetFeedArticlesAsync(int id)
{
if (getFeedArticlesCts != null)
getFeedArticlesCts.Cancel();
using (getFeedArticlesCts = new CancellationTokenSource())
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
这是当前开发的一个领域,因此请进行改进或API建议!
归档时间: |
|
查看次数: |
3062 次 |
最近记录: |