异步MVVM - 如何更改NotifyTaskCompletion.Result

时间:2016-04-30 14:49:18

标签: c# wpf mvvm async-await

我的问题源于Stephen Cleary的an article

基本上,有一个标签

<Label Content="{Binding UrlByteCount.Result}"/>

并且由viewmodel c.tor

设置
UrlByteCount = new NotifyTaskCompletion<int>(
                MyStaticService.CountBytesInUrlAsync("http://www.example.com"));

到目前为止一切顺利。 现在我做了一个微不足道的改变:

 UrlByteCount = new NotifyTaskCompletion<int>(MyStaticService.ImmediateSet(-1));

已定义

public static Task<int> ImmediateSet(int res)
{
    var tcs = new TaskCompletionSource<int>();
    tcs.SetResult(res);
    return tcs.Task;
}

显然标签会立即显示-1。 好的,然后我添加一个带有viewmodel命令绑定的按钮,因为我想在单击按钮时设置标签

跳过所有礼仪部分(委托命令等),核心功能又是:

private void TestLogic()
{
    UrlByteCount = new NotifyTaskCompletion<int>( // FIX ME
        MyStaticService.CountBytesInUrlAsync("http://www.example.com")); // FIX ME
}

我完全清楚没有工作,而且标签的内容仍然是-1,但我要问哪个是最好的解决这个问题的方法?

问题的第二部分。

假设您已经找到第一部分的解决方案,并且单击按钮异步更改标签的内容(维护ui响应性),您能否确认以下代码是否是一致的方式防止&#34;双击&#34; (即&#34;多次执行&#34;)?

private async void TestLogic()
{
    canRun = false;
    ((DelegateCommand)TestCommand).RaiseCanExecuteChanged();
    await FoundASolution();
    canRun = true;
    ((DelegateCommand)TestCommand).RaiseCanExecuteChanged();
}

private async Task<int> FoundASolution()
{
    await Task.Delay(TimeSpan.FromSeconds(10));
    return 21;
}

1 个答案:

答案 0 :(得分:0)

假设您在UrlByteCount setter中提升了属性更改事件,您的代码应该可以正常工作。绑定到UrlByteCount.Result的事实并不意味着当您仅更改UrlByteCount时,绑定不会刷新 - 它会。

至于你的第二部分 - 在启动长时间运行操作之前,可以通过Command.CanExecute false来禁用按钮并通过Command.CanExecuteChanged事件通知此事件。即使操作因异常而失败,也要确保再次启用它(因此请在try-finally块中包装)。您可能想要通知用户有关错误并允许他修复它(或者只是稍等一下,如果错误是网络故障),并重试操作,这在您的情况下是不可能的 - 按钮将保持禁用状态如果有错误。