异步MVVM - 如何更改NotifyTaskCompletion.Result

时间:2022-12-09 21:14:05

My question stems from an article of Stephen Cleary.

我的问题源于Stephen Cleary的一篇文章。

Basically, there is a Label

基本上,有一个标签

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

and it's set by viewmodel c.tor

它由viewmodel c.tor设置

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

So far so good. Now I do a trivial change:

到现在为止还挺好。现在我做了一个微不足道的改变:

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

having defined

定义了

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

Obviously the label immediately shows -1. Ok, then I add a button with viewmodel command binding, because I want to set the label when I click the button.

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

skipping all the ceremonial part (delegate command, etc.), the core function is again:

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

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

I'm perfectly aware that it doesn't work and that the label's content will remain -1, but I'm asking which is the best approach to fix this?

我完全清楚它不起作用,标签的内容将保持-1,但我问的是解决这个问题的最佳方法是什么?

Second part of the question.

Assuming you've already found a solution to the first part and the click on the button asynchronously changes the label's content (maintaining ui responsiveness), can you confirm if the following code is a consistent way to prevent "double clicking" (i.e. "multiple executions")?

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

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 个解决方案

#1


0  

Your code should work fine assuming you raise property changed event in your UrlByteCount setter. The fact that you bind to UrlByteCount.Result does not mean binding will not refresh when you only change UrlByteCount - it will.

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

As for your second part - it's ok to disable button via making Command.CanExecute false and notifying about this via Command.CanExecuteChanged event, before starting long running operation. Just ensure you enable it back again even if operation fails with exception (so wrap inside try-finally block). You may want to notify user about error and allow him to fix it (or just wait a bit, if error is network failure for example), and retry operation, which won't be possible in your case - button will stay disabled in case of error.

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

#1


0  

Your code should work fine assuming you raise property changed event in your UrlByteCount setter. The fact that you bind to UrlByteCount.Result does not mean binding will not refresh when you only change UrlByteCount - it will.

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

As for your second part - it's ok to disable button via making Command.CanExecute false and notifying about this via Command.CanExecuteChanged event, before starting long running operation. Just ensure you enable it back again even if operation fails with exception (so wrap inside try-finally block). You may want to notify user about error and allow him to fix it (or just wait a bit, if error is network failure for example), and retry operation, which won't be possible in your case - button will stay disabled in case of error.

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