Home > Net >  Relay Command CanExecute is only invoked in the viewmodels constuctor once but won't invoke aga
Relay Command CanExecute is only invoked in the viewmodels constuctor once but won't invoke aga

Time:04-28

What I want to do: When my view is loaded, one can see several textboxes that are compulsory fields(marked red). For as long as those textboxes are not filled out, the button "NEXT" is disabled, otherwise enabled: enter image description here

The XAML for the button:

  <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>

What I tried: On the internet I read about the RelayCommand and hence decided to add it to my project to achieve the above mentioned goal. In the Viewmodel's constructor I included it like this:

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

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

As you can see, I used two methods called CopyTemplate() and CanCopyTemplate() . For now, it does not matter what the first one does but the latter is supposed to return true when all compulsory fields are filled out and false if not. For this example I only used one compulsory field for reasons of simplicity:

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;
            
}

However, when I fill out SelAnrede (string that is bound to the Combobox Selected Item property with Update Source Trigger=On Property Changed, the button remains disabled. What am I missing? Why is the CanExecuteChanged()-Method not invoked when I change the SelItem property in the view? Why is the CanCopyTemplate()-method not invoked again?

Here is the RelayCommand-Class for a better overview:

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
    }

CodePudding user response:

Whenever a property whose value is checked in the CanCopyTemplate method of the command is set, you should call a method of the command that raises its CanExecuteChanged event.

So, for example, the setter of your SelAnrede property should be implemented something like this:

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

The CanExecuteChanged event is not something that is raised "automatically" but most implementations of ICommand out there have a method that raises it for you. You only need to make sure that you actually call it.

  • Related