NotifyOnValidationError如何最终调用CanExecute(以及为什么它不能与MVVM Light RelayCommand一起使用)

时间:2016-04-21 12:00:53

标签: wpf mvvm prism mvvm-light

也许是有史以来最长的问题标题!因为这是一个两部分的问题。

(1)我不明白如何设置NotifyOnValidationError =" True"可以触发我的CanExecute更新。我需要了解一些神奇的内容。某人(事物)订阅我的ICommand的CanExecuteChanged事件,但调用堆栈指向外部代码,所以我无法弄清楚发生了什么。

(2)也许最重要的后续问题是:为什么它在MVVM Light RelayCommand中不起作用! CanExecute仅在初始化时调用一次,然后再也不会调用。在MVVM Light中查看RelayCommand的源代码并没有发现与我自己的实现相比的任何阻塞差异。我应该提一下,Prism的DelegateCommand似乎也不起作用。

(Bonus)也许我正在以错误的方式接近这个问题?我只是想基于验证失败来启用/禁用按钮。

XAML(摘录):

    <TextBox Grid.Column="1" Grid.Row="0">
        <Binding Path="X" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">
            <Binding.ValidationRules>
                <ExceptionValidationRule></ExceptionValidationRule>
            </Binding.ValidationRules>
        </Binding>
    </TextBox>

    <Button Grid.Column="1" Grid.Row="3" Command="{Binding CalculateCommand}">
        Calculate
    </Button>

RelayCommand:

public class MyRelayCommand : ICommand
{
    readonly Action<object> Execute_;
    readonly Predicate<object> CanExecute_;

    public MyRelayCommand(Action<object> Execute, Predicate<object> CanExecute)
    {
        if (Execute == null)
            throw new ArgumentNullException("No action to execute for this command.");

        Execute_ = Execute;
        CanExecute_ = CanExecute;
    }

    public bool CanExecute(object parameter)
    {
        return (CanExecute_ == null) ? true : CanExecute_(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        Execute_(parameter);
    }
}

视图模型:

    private DelegateCommand _calculateCommmand;
    public DelegateCommand CalculateCommand
    {
        get
        {
            return _calculateCommmand ?? (_calculateCommmand = new DelegateCommand(
            () =>
            {
                Sum = X + X;
            },
            () =>
            {
                try
                {
                    Convert.ChangeType(X, TypeCode.Byte);
                    return true;
                }
                catch
                {
                    return false;
                }
            }));
        }
    }

PS:如果您想购买我的X + X程序,请发送电子邮件至sales@xplusx.com

3 个答案:

答案 0 :(得分:1)

(2)我自己想出了这个。您可以选择从两个不同的命名空间中包含RelayCommand,确保使用

using GalaSoft.MvvmLight.CommandWpf;

我仍然在寻找一个很好的答案(1),管道如何根据验证错误引发CanExecutetChanged。

答案 1 :(得分:0)

我认为这取决于ICommand实施。在你的,我看到public event EventHandler CanExecuteChanged,你告诉CommandManager处理命令CanExecute()方法的调用。如果没有CommandManager,您必须自己处理,例如通过为您的ICommand实现提供public void RaiseCanExecuteChanged()方法,ViewModel必须为其认为需要重新计算的每个命令调用该方法,例如:在ViewModel的OnPropertyChanged内。示例:https://codereview.stackexchange.com/questions/124361/mvvm-am-i-doing-it-right

所以CommandManager为你带来了魔力。只要您调用ViewModel的PropertyChanged事件,就会出现&#34;外部代码&#34;处理受影响的命令并要求他们获得新的CanExecute()值。

答案 2 :(得分:0)

(1)我认为是这样的。

  1. 当我们将RelayCommand:ICommand绑定到Button.Command时,绑定过程还会将一个事件处理程序附加到ICommand.CanExecuteChanged。这是默认行为。
  2. 传递给CanExecutedChanged的eventhandler将传递并附加到静态事件CommandManager.RequerySuggested。
  3. 当发生验证错误且设置了NotifyOnValidationError时,外部力量或jedi将引发RequerySuggested事件,该事件将广播到所有活动命令。
  4. 按钮接收事件,因此调用CanExecute以确定它是否禁用/启用按钮。
  5. 我想更多地了解上面的第三个要点,所以我会将问题保持一段时间,让专家有机会参与其中。