question

JerryM-2071 avatar image
0 Votes"
JerryM-2071 asked NickG-0379 commented

MVVM, RelayCommand : ICommand

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();
         }
     }
windows-wpf
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

PeterFleischer-3316 avatar image
1 Vote"
PeterFleischer-3316 answered NickG-0379 commented

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




x.gif (59.8 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks a lot!

0 Votes 0 ·
JerryM-2071 avatar image
0 Votes"
JerryM-2071 answered PeterFleischer-3316 commented

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 ?

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I correct my code.

0 Votes 0 ·
JerryM-2071 avatar image
0 Votes"
JerryM-2071 answered PeterFleischer-3316 commented

and one more "queer" question:

where is the line:

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

and where is the line:

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



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

That is not necessary, see ICommand.

0 Votes 0 ·
JerryM-2071 avatar image
0 Votes"
JerryM-2071 answered PeterFleischer-3316 commented

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

here ????

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

the are no information of the:

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

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

See ICommand.CanExecuteChanged Event ->

Occurs when changes occur that affect whether or not the command should execute. A command source calls CanExecute on the command when this event occurs.

In my demo I call RelayCommand.RaiseCanExecuteChanged -> CanExecuteChanged?.Invoke(... -> RelayCommand.CanExecute -> _canExecute(parameter) -> CanCmdExec2 -> return _enabled

0 Votes 0 ·