Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 要正确运行异步方法,是否需要relaycommand的异步版本_C#_.net_Asynchronous_Async Await_Relaycommand - Fatal编程技术网

C# 要正确运行异步方法,是否需要relaycommand的异步版本

C# 要正确运行异步方法,是否需要relaycommand的异步版本,c#,.net,asynchronous,async-await,relaycommand,C#,.net,Asynchronous,Async Await,Relaycommand,我在viewmodel中定义了以下代码。我认为类型为Func的SaveAsync正在转换为Action,因为RelayCommand执行的操作不是Func,但我不清楚这意味着什么 1) 是否需要用异步版本(RelayCommandAsync)替换RelayCommand? 2) 当前代码在异步方面做了什么? 3) 如果我可以/应该改变什么来改进/纠正它呢 private ICommand _saveCommand; public ICommand SaveCommand { get {

我在viewmodel中定义了以下代码。我认为类型为
Func
的SaveAsync正在转换为Action,因为RelayCommand执行的操作不是
Func
,但我不清楚这意味着什么

1) 是否需要用异步版本(RelayCommandAsync)替换RelayCommand? 2) 当前代码在异步方面做了什么? 3) 如果我可以/应该改变什么来改进/纠正它呢

private ICommand _saveCommand;
public ICommand SaveCommand
{
    get { return _saveCommand ?? (_saveCommand = new RelayCommand(async () => await SaveAsync(), CanSave)); }
}

public bool CanSave()
{
    return !IsBusy;
}

private async Task SaveAsync()
{
    IsBusy = true;

    try
    {
        await _service.SaveAsync(SomeProperty); 
    }
    catch ( ServiceException ex )
    {
        Message = "Oops. " + ex.ToString();
    }
    finally
    {
        IsBusy = false;
    }
}
谢谢

编辑:经过一些实验后,似乎异步方法本身也能正常工作。lambda中是否包含async/await,以及该方法是否定义为
async Task
async void
都没有区别

但是,不能正常工作的是自动启用/禁用与命令的控件绑定的
canExecute
谓词功能。发生的情况是,当异步方法运行时,按钮被正确地禁用,但之后它没有被启用。我必须单击窗口上的某个位置一次,然后它再次启用


因此,完整的功能似乎需要一个异步版本的RelayCommand,也就是说,
canExecute
可以正确地执行它。

我认为您不需要一个异步版本的relay命令。您的实现看起来不错。它有用吗

如果要测试主体是否在异步运行,请添加wait task.delay(20000)并查看UI在命令运行时是否保持响应

是否需要用异步版本(RelayCommandAsync)替换RelayCommand

否,
RelayCommand
将在此处按需要工作

当前代码在异步方面做了什么

发生的情况是,当重载解析在编译时启动时,它选择执行
操作的重载,这意味着您的方法将被转换为
异步void
,这就是代码编译的原因

3) 如果我可以/应该改变什么来改进/纠正它呢

private ICommand _saveCommand;
public ICommand SaveCommand
{
    get { return _saveCommand ?? (_saveCommand = new RelayCommand(async () => await SaveAsync(), CanSave)); }
}

public bool CanSave()
{
    return !IsBusy;
}

private async Task SaveAsync()
{
    IsBusy = true;

    try
    {
        await _service.SaveAsync(SomeProperty); 
    }
    catch ( ServiceException ex )
    {
        Message = "Oops. " + ex.ToString();
    }
    finally
    {
        IsBusy = false;
    }
}
存在异步委托命令的实现。你可以找到一个。需要注意的一件重要事情是异常处理。在绑定到WPF控件的异步
ICommand
中出现未处理异常的情况下,该异常将传播到绑定器并未处理且未被注意

1) 是否需要用异步版本(RelayCommandAsync)替换RelayCommand

不必这样,但你应该考虑一下。

2) 当前代码在异步方面做了什么

它正在创建一个
异步void
lambda。这是有问题的,因为
async void
不能很好地处理异常。如果您确实将
RelayCommand
与异步代码一起使用,那么您肯定希望使用
try
/
catch
,就像您代码中的一样

3) 如果我可以/应该改变什么来改进/纠正它呢

private ICommand _saveCommand;
public ICommand SaveCommand
{
    get { return _saveCommand ?? (_saveCommand = new RelayCommand(async () => await SaveAsync(), CanSave)); }
}

public bool CanSave()
{
    return !IsBusy;
}

private async Task SaveAsync()
{
    IsBusy = true;

    try
    {
        await _service.SaveAsync(SomeProperty); 
    }
    catch ( ServiceException ex )
    {
        Message = "Oops. " + ex.ToString();
    }
    finally
    {
        IsBusy = false;
    }
}
如果这是代码中唯一的异步命令,我会说它很好。但是,如果你发现你的应用程序中有几个类似语义的异步命令,那么你应该考虑编写一个<代码> RelayCudidAsAcc<<代码> < < /P> 目前还没有标准模式;我在一篇文章中概述了几种不同的方法。就个人而言,至少我在我的应用程序中定义了一个
IAsyncCommand
,我从虚拟机中公开了它(很难对异步
ICommand
进行单元测试)

但是,不能正常工作的是canExecute谓词功能,该功能会自动启用/禁用与命令的控件绑定


假设
RelayCommand.CanExecuteChanged
正在委托给
CommandManager
,那么您可以调用
CommandManager.InvalidateRequestSuggested
在设置
IsBusy
否之后。在绑定上设置IsAsync。像这样:

<Button Command="{Binding DoCommand, IsAsync=True}" />

IsBusy Implement iNotifyPropertyChanged err您的虚拟机是否执行此操作,属性是否调用您调用事件的方法?还是dp?在这种情况下,您必须在UI线程上更改它。只是这是处理这个问题的典型错误。