MVVM, RelayCommand : ICommand

JerryM 1,131 Reputation points
2021-06-12T06:42:16.753+00:00

Hello,
1/ for what is good the "public event EventHandler CanExecuteChanged" in my "public class RelayCommand : ICommand" ?
2/ Who is receiver/recipient of the event "RequerySuggested" ???
3/ What contains the "value" ?
Is there something like "global scheme of all such processes in A0 paper size" ?
Jerry

    public class RelayCommand : ICommand
    {
        private Action commandTask;

        public RelayCommand(Action t_workToDo)
        {
            commandTask = t_workToDo;
        }

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


        protected void OnCanExecuteChanged(Object sender, EventArgs e)
        {
           // this.CanExecuteChanged?.Invoke(this, new EventArgs() );
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(Object parameter)
        {
            commandTask();
        }
    }
Developer technologies | Windows Presentation Foundation
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2021-06-12T07:37:59.04+00:00

    Hi,
    EventHandler CanExecuteChanged you can use to raise the CanExecuteChanged event to indicate that the return value of the CanExecute method has changed. Try following demo.

    XAML:

    <Window x:Class="WpfApp1.Window069"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp069"  
            mc:Ignorable="d"  
            Title="Window069" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
        <StackPanel>  
        <Button Content="Click to change enabled bext button" Command="{Binding Cmd1}"/>  
        <Button Content="disabled / enabled button" Command="{Binding Cmd2}"/>  
      </StackPanel>  
    </Window>  
    

    And classes:

     using System;  
     using System.Diagnostics;  
     using System.Windows;  
     using System.Windows.Input;  
          
     namespace WpfApp069  
     {  
       public class ViewModel  
       {  
         private RelayCommand _cmd1;  
         public ICommand Cmd1  
         {  
           get  
           {  
             Debug.Print("Getter property Cmd1");  
             if (this._cmd1 == null) this._cmd1=new RelayCommand(CmdExec1, CanCmdExec1);  
             return this.cmd1;  
           }  
         }  
          
         private bool CanCmdExec1(object obj) => true;  
          
         private void CmdExec1(object obj)  
         {  
           this._enabled = !_enabled;  
           this._cmd2.RaiseCanExecuteChanged();  
           Debug.Print("CmdExec1");  
         }  
          
         private RelayCommand _cmd2;  
         public ICommand Cmd2  
         {  
           get  
           {  
             Debug.Print("Getter property Cmd2");  
             if (this._cmd2 == null) this._cmd2=new RelayCommand(CmdExec2, CanCmdExec2);  
             return this._cmd2;  
           }  
         }  
          
         private bool _enabled;  
          
         private bool CanCmdExec2(object obj) => _enabled;  
          
         private void CmdExec2(object obj) => Debug.Print("CmdExec2");  
       }  
    
      /// <summary>  
      /// A command whose sole purpose is to relay its functionality   
      /// to other objects by invoking delegates.   
      /// The default return value for the CanExecute method is 'true'.  
      /// <see cref="RaiseCanExecuteChanged"/> needs to be called whenever  
      /// <see cref="CanExecute"/> is expected to return a different value.  
      /// </summary>  
      public class RelayCommand : ICommand  
      {  
        #region Private members  
        /// <summary>  
        /// Creates a new command that can always execute.  
        /// </summary>  
        private readonly Action<object> _execute;  
      
        /// <summary>  
        /// True if command is executing, false otherwise  
        /// </summary>  
        private readonly Predicate<object> _canExecute;  
        #endregion  
      
        /// <summary>  
        /// Initializes a new instance of <see cref="RelayCommand"/> that can always execute.  
        /// </summary>  
        /// <param name="execute">The execution logic.</param>  
        public RelayCommand(Action<object> execute) : this(execute, canExecute: null) { }  
      
        /// <summary>  
        /// Initializes a new instance of <see cref="RelayCommand"/>.  
        /// </summary>  
        /// <param name="execute">The execution logic.</param>  
        /// <param name="canExecute">The execution status logic.</param>  
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)  
        {  
          if (execute == null) throw new ArgumentNullException("execute");  
          this._execute = execute;  
          this._canExecute = canExecute;  
        }  
      
        /// <summary>  
        /// Raised when RaiseCanExecuteChanged is called.  
        /// </summary>  
        public event EventHandler CanExecuteChanged;  
      
        /// <summary>  
        /// Determines whether this <see cref="RelayCommand"/> can execute in its current state.  
        /// </summary>  
        /// <param name="parameter">  
        /// Data used by the command. If the command does not require data to be passed, this object can be set to null.  
        /// </param>  
        /// <returns>True if this command can be executed; otherwise, false.</returns>  
        public bool CanExecute(object parameter) => this._canExecute == null ? true : this._canExecute(parameter);  
      
        /// <summary>  
        /// Executes the <see cref="RelayCommand"/> on the current command target.  
        /// </summary>  
        /// <param name="parameter">  
        /// Data used by the command. If the command does not require data to be passed, this object can be set to null.  
        /// </param>  
        public void Execute(object parameter) => this._execute(parameter);  
      
        /// <summary>  
        /// Method used to raise the <see cref="CanExecuteChanged"/> event  
        /// to indicate that the return value of the <see cref="CanExecute"/>  
        /// method has changed.  
        /// </summary>  
        public void RaiseCanExecuteChanged() => this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);  
      }  
    }  
    

    Result:

    105008-x.gif

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. JerryM 1,131 Reputation points
    2021-06-13T07:03:32.99+00:00

    it is nice example...
    why there is:

    Row 15: return new RelayCommand(CmdExec1, CanCmdExec1);

    and

    Row 34: if (_cmd2 == null) _cmd2=new RelayCommand(CmdExec2, CanCmdExec2);

    what if the row 15 is called more than once ?


  2. JerryM 1,131 Reputation points
    2021-06-13T08:27:54.887+00:00

    and one more "queer" question:

    where is the line:

    _cmd2.CanExecuteChanged += CanCmdExec2(); ???

    and where is the line:

    _cmd1.CanExecuteChanged += CanCmdExec1(); ???


  3. JerryM 1,131 Reputation points
    2021-06-13T13:03:26.367+00:00

    "That is not necessary, see ICommand." .... where I have to see to ???

    here ????

    https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.icommand?view=net-5.0

    the are no information of the:

    _cmd2.CanExecuteChanged += CanCmdExec2(); ???


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.