[Transfer] [WPF] Three commands of MVVM mode

1.DelegateCommand

2.RelayCommand

3.AttachbehaviorCommand

Because the MVVM mode is suitable for WPF and SL, there are some small differences in these three modes. For example, the CommandManager method under RelayCommand is under WPF and cannot be used under SL. However, I think the basic ideas in these three methods are the same. They all come from the articles written by that foreign expert. The main difference lies in the binding and use of controls in VIEW. The slightly different attachbehaviorcommand is a design pattern in prism4, and the difference is a bit big. But I think the most convenient thing is this DelegateCommand.

DelegateCommand

 /// <summary>
    /// Delegatecommand, this kind of WPF.SL can be used, and the trigger of INTERACTION is directly used in VIEW. Relatively reliable and suitable for different UIElement controls
    /// </summary>
    public class DelegateCommand : ICommand
    {
        Func<object, bool> canExecute;
        Action<object> executeAction;
        bool canExecuteCache;

        public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
        {
            this.executeAction = executeAction;
            this.canExecute = canExecute;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            bool temp = canExecute(parameter);

            if (canExecuteCache != temp)
            {
                canExecuteCache = temp;
                if (CanExecuteChanged != null)
                {
                    CanExecuteChanged(this, new EventArgs());
                }
            }

            return canExecuteCache;
        }

        public event EventHandler CanExecuteChanged;

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

        #endregion
    }

This class can probably be understood in this way, the action and func in the constructor, action is responsible for determining whether to execute the command, and action is the method to be executed after triggering the command. This is the easiest way to understand, but for me who is just familiar with command, this is the easiest way to remember and learn. You can find explanations of methods and events implemented using the ICommand interface by searching, but it is still a bit obscure to understand at first.

The following is an example of using this command in VM. Bind a button control, the simplest example. cm1Click is the fuc in the constructor, which is responsible for executing methods that respond to events. Cancm1Click is the action in the constructor, responsible for determining whether the response event of this Command is executed. No judgment expression is used here, and a true is directly assigned.

public class TestViewModels:INotifyPropertyChanged
{
        public TestViewModels()
        {
            ...
            cm1click = new DelegateCommand(cm1Click,Cancm1Click); //Initialize delegatecommand
            
        }
       ....

       //DelegateCommand

        #region command1

        public ICommand cm1click { get; set; }
        public void cm1Click(object param)
        {
            MessageBox.Show("CM1 clicked!");
        }

        private bool Cancm1Click(object param)
        {
            return true;
        }

        #endregion command1
       ...
}

In XAML, use interaction to bind this event instead of using command in button. This has the advantage that it is very intuitive and can respond to many other events.

<Button x:Name="BTN_CM1" Content="DelegateCommand" Height="115" Width="148" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding cm1click}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

RelayCommand

RelayCommand is originally a custom command used under WPF, mainly because it uses event management functions, which is not available under SL. However, if this part of the code is modified, it can also be used under SL, which is similar to the implementation idea under WPF.

Let’s take a look at the definition of RelayCommand first. There are 2 types in total.

public class RelayCommand<T> : ICommand
    {
        public RelayCommand(Action<T> execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute((T)parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add{}
            remove{}
            //add
            //{
            // if (_canExecute != null)
            // CommandManager.RequerySuggested + = value;
            //}
            //remove
            //{
            // if (_canExecute != null)
            // CommandManager.RequerySuggested -= value;
            //}
        }

        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }

        readonly Action<T> _execute = null;
        readonly Predicate<T> _canExecute = null;

        bool ICommand.CanExecute(object parameter)
        {
            throw new NotImplementedException();
        }

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

        void ICommand.Execute(object parameter)
        {
            throw new NotImplementedException();
        }
    }

The first is to use the generic Relaycommand definition

public class RelayCommand : ICommand
    {
        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }
        public event EventHandler CanExecuteChanged
        { //The implementation is commented out here so that it can also be used under SL.
            add { }
            remove { }
            //add
            //{
            // if (_canExecute != null)
            // CommandManager.RequerySuggested + = value;
            //}
            //remove
            //{
            // if (_canExecute != null)
            // CommandManager.RequerySuggested -= value;
            //}
        }

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

        readonly Action _execute;
        readonly Func<bool> _canExecute;
    }

The second is the most commonly used definition. You can see that the commmandmanager method is commented out in the CanExecuteChanged event, and you can use this class under SL, and there seems to be no problem now.

In terms of code, there is basically no difference between Relaycommand and delegatcommand. They also implement the two parameters func and action. The basic idea is the same.

The biggest difference between them is the calling method of the front end. delegatecommand uses the interaction in expression’s SDK to bind events, and this is directly bound through the command attribute of buttonbase. Therefore, it can only execute click events, so the scope of use is relatively limited. However, if interaction is used to bind events If so, the implementation is actually the same as delegatecommand. However, in order to summarize the study, we should distinguish them separately.

Front-end XAML code

<Button x:Name="BTN_CM2" Content="Command2" Height="103" HorizontalAlignment="Left" Margin="115,123,0,0" VerticalAlignment=" Top" Width="109" Command="{Binding command2}" />

Backstage

private ICommand _command2;
        public ICommand command2
        {
            get
            {
                if (this._command2 == null)
                {
                    this._command2 = new RelayCommand(
                        () => this.cm2Click(),
                        () => this.Cancm2Click);
                }

                return this._command2;
            }
            set{}
        }

        public bool Cancm2Click
        {
            get { return true; }
        }

        public void cm2Click()
        {
            MessageBox.Show("CM2 Clicked!");
        }

Original address: http://www.cnblogs.com/matoo/archive/2012/04/14/2447159.html

   http://www.cnblogs.com/matoo/archive/2012/04/17/2452987.html