gpt4 book ai didi

c# - 在 MVVM 中使用 DelegateCommand 的异步 CanExecute 方法

转载 作者:行者123 更新时间:2023-12-03 10:22:13 29 4
gpt4 key购买 nike

我有一个简单的 DelegateCommand 类,如下所示:

public class DelegateCommand<T> : System.Windows.Input.ICommand where T : class
{
public event EventHandler CanExecuteChanged;

private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;

public DelegateCommand(Action<T> execute) : this(execute, null)
{
}

public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
this._execute = execute;
this._canExecute = canExecute;
}

public bool CanExecute(object parameter)
{
if (this._canExecute == null)
return true;

return this._canExecute((T)parameter);
}

public void Execute(object parameter)
{
this._execute((T)parameter);
}


public void RaiseCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}

我正在使用 GalaSoft.MvvmLight为了验证,通常我会在 View 构造函数中做这样的事情:
this.MyCommand = new DelegateCommand<object>(o => {
//Do execute stuff
}, o =>
{
//Do CanExecute stuff
var validateResult = this.Validator.ValidateAll();
return validateResult.IsValid;
});

public DelegateCommand<object> MyCommand { get; }

当我有一个简单的验证检查时,这一切都很好:
this.Validator.AddRequiredRule(() => this.SomeProperty, "You must select.......");

但现在我需要一个验证方法来执行一个长时间运行的任务(在我的例子中是一个 WebService 调用)所以当我想做这样的事情时:
this.Validator.AddAsyncRule(async () =>
{
//Long running webservice call....
return RuleResult.Assert(true, "Some message");
});

因此声明这样的命令:
this.MyCommand = new DelegateCommand<object>(o => {
//Do execute stuff
}, async o =>
{
//Do CanExecute ASYNC stuff
var validateResult = await this.Validator.ValidateAllAsync();
return validateResult.IsValid;
});

因为标准的 ICommand 实现似乎无法处理异步场景,所以我有点担心。

无需过多考虑,您似乎可以重新编写 DelegateCommand 类以支持此类功能,但我已经研究了 Prism 处理此 https://prismlibrary.github.io/docs/commanding.html 的方式。 , 但是似乎它们也不支持异步 CanExecute 方法。

那么,有没有办法解决这个问题?或者在尝试使用 ICommand 从 CanExecute 运行 Async 方法时是否存在根本性的问题?

最佳答案

Andy's answer很棒,应该被接受。 TL;DR 版本是“你不能使 CanExecute 异步”。

我只是在这里回答这部分问题的更多信息:

is there something fundamentally broken in trying to run an Async method from CanExecute using ICommand?



是的,肯定有。

从您正在使用的 UI 框架的角度考虑这一点。当操作系统要求它绘制屏幕时,框架必须显示一个 UI,它必须显示它 现在 .绘制屏幕时没有时间进行网络调用。 View 必须能够随时立即显示。 MVVM 是一种模式,其中 ViewModel 是用户界面的逻辑表示, View 和 VM 之间的数据绑定(bind)意味着 ViewModel 需要立即同步地将其数据提供给 View 。因此,ViewModel 属性需要是常规数据值。
CanExecute是命令的一个设计奇特的方面。从逻辑上讲,它充当数据绑定(bind)属性(但带有参数,这就是我认为它被建模为方法的原因)。当 OS 要求 UI 框架显示其窗口,UI 框架要求其 View 渲染(例如)一个按钮,而 View 向 ViewModel 询问该按钮是否被禁用时,必须立即同步返回结果。

换句话说:UI 本质上是同步的。您需要采用不同的 UI 模式来将同步 UI 代码与异步事件结合起来。例如,“正在加载...”用于异步加载数据的 UI,或用于异步验证的 disable-buttons-with-help-text-until-validated(如本问题所示),或带有失败通知的基于队列的异步请求系统.

关于c# - 在 MVVM 中使用 DelegateCommand 的异步 CanExecute 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58040651/

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