中继命令 CanExecute 仅在视图模型构造函数中调用一次,但在属性更改时不会再次调用

Relay Command CanExecute is only invoked in the viewmodels constuctor once but won't invoke again when Properties are changed

我想做什么: 加载我的视图时,可以看到几个必填字段(标记为红色)的文本框。只要这些文本框未填写,“下一步”按钮就会被禁用,否则会启用:

按钮的XAML:

  <Grid Grid.Row="10" Grid.RowSpan="2" Grid.Column="11" Grid.ColumnSpan="2">
                <Button ToolTip="Die Pflichtfelder bitte ausfüllen!" Content="WEITER ZU GRUNDLAGEN" Command="{Binding AngebotKopieren}" Grid.ColumnSpan="2"></Button>
            </Grid>

我试过的: 在 Internet 上,我阅读了有关 RelayCommand 的信息,因此决定将其添加到我的项目中以实现上述目标。 在 Viewmodel 的构造函数中,我像这样包含它:

public MyViewModel()
{
    AngebotKopieren = new RelayCommand(CopyTemplate, CanCopyTemplate);
}

private ICommand _angebotKopieren;
        public ICommand AngebotKopieren
        {
            get { return _angebotKopieren; }
            set { _angebotKopieren = value; OnPropertyChanged("AngebotKopieren"); }
        }

如您所见,我使用了两个方法 CopyTemplate()CanCopyTemplate() 。现在,第一个做什么并不重要,但后者应该 return 在所有必填字段都已填写时为真,否则为假。对于这个例子,为了简单起见,我只使用了一个必填字段:

private bool CanCopyTemplate(object obj)
{
    if(//(String.IsNullOrEmpty(Nachname) && String.IsNullOrEmpty(Vorname) && String.IsNullOrEmpty(Angebotstitel) && 
        String.IsNullOrEmpty(SelAnrede) //&& String.IsNullOrEmpty(StrasseWohnort) && String.IsNullOrEmpty(PLZ_Wohnort) 
        //&& String.IsNullOrEmpty(Wohnort)))
        )
    {
        return false;
    }
              
        return true;
            
}

但是,当我填写 SelAnrede(绑定到 Combobox Selected Item 属性 with Update Source Trigger=On 属性 的字符串已更改时,该按钮仍处于禁用状态。 我错过了什么?为什么在视图中更改 SelItem 属性 时未调用 CanExecuteChanged() 方法?为什么 CanCopyTemplate() 方法不再被调用?

这里是 RelayCommand-Class 以获得更好的概述:

public class RelayCommand : ICommand
    {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Konstruktoren

        /// <summary>
        /// Erzeugt ein neues Command, das immer ausführen kann.
        /// </summary>
        /// <param name="execute">Die Ausführungslogik...</param>
        public RelayCommand(Action<object> execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Erzeugt ein neues Command
        /// </summary>
        /// <param name="execute">Die Ausführungslogik...</param>
        /// <param name="canExecute">Die Logik zum Ausführungsstatus...</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion // Konstruktoren

        #region ICommand Members

        [DebuggerStepThrough]
        public bool CanExecute(object parameters)
        {
            return _canExecute == null ? true : _canExecute(parameters);
        }

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

        event EventHandler ICommand.CanExecuteChanged
        {
            add
            {
                //throw new NotImplementedException();
            }

            remove
            {
                //throw new NotImplementedException();
            }
        }

        public void Execute(object parameters)
        {
            _execute(parameters);
        }

        #endregion // ICommand Members
    }

每当设置了在命令的 CanCopyTemplate 方法中检查其值的 属性 时,您应该调用引发其 CanExecuteChanged 事件的命令的方法。

因此,例如,SelAnrede 属性 的 setter 应该像这样实现:

private string _selAnrede;
public string SelAnrede
{
    get { return _selAnrede; }
    set
    {
        _selAnrede = value;
        OnPropertyChanged(nameof(SelAnrede));
        CommandManager.InvalidateRequerySuggested();
    }
}

CanExecuteChanged 事件不是“自动”引发的事件,但大多数 ICommand 的实现都有一个为您引发它的方法。你只需要确定你真的调用了它。