zoukankan      html  css  js  c++  java
  • 【转】【WPF】MVVM模式的3种command

    1.DelegateCommand

    2.RelayCommand

    3.AttachbehaviorCommand

    因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCommand下面的CommandManager方法就是WPF下面的,SL下面无法使用,不过我认为这3种方法中的基本思路都如出一辙,都是出自那位外国牛人的文章里面。主要的区别在于和VIEW中的控件的绑定使用上。有点不同的attachbehaviorcommand是prism4里面的一种设计模式,这个区别有点大。但我自己觉得最方便的还是这个DelegateCommand。

    DelegateCommand

        /// <summary>
        /// Delegatecommand,这种WPF.SL都可以用,VIEW里面直接使用INTERACTION的trigger激发。比较靠谱,适合不同的UIElement控件
        /// </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
        }

    这个类大概可以这样来理解,构造函数中的action和func,action负责判断是否执行这个command,action就是触发这个command之后要执行的方法。这样理解最浅显,但对刚熟悉command的我来讲,这样最方便记忆和学习,为了使用ICommand接口实现的方法和事件的解释搜搜就可以找到,但是刚开始理解起来还是有点晦涩。

    下面是VM里面用这个command的例子。绑定了一个button控件,最简单例子。cm1Click就是构造函数里面的fuc,负责执行响应事件的方法。Cancm1Click就是构造函数里面的action,负责判断这个Command的响应事件是否执行,这里没有用到判断式,直接赋了一个true.

    public class TestViewModels:INotifyPropertyChanged
    {
            public TestViewModels()
            {
                ......
                cm1click = new DelegateCommand(cm1Click,Cancm1Click);   //初始化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
           ......
    }

    在XAML里面,用interaction来绑定这个事件,而不是在button里面用command来绑定,这样做有个好处,就是非常直观,并且可以响应其他的很多事件

    <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本来是WPF下面用的一种自定义的command,主要是它用到了事件管理函数,这个SL下面是没有的。不过这部分代码如果修改一下,也可以在SL下面使用,和WPF下面的实现思路差不多。

    先看下RelayCommand的定义,一共有2种。

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

    第一种是采用泛型的Relaycommand定义

    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
            {   //这里把实现注释掉了,这样在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;
        }

    第二种就是最常用的定义,可以看到在CanExecuteChanged事件里面把commmandmanager方法给注释掉了,就可以在SL下面使用这个类,而且现在看好像也没有什么问题。

    在代码上看,Relaycommand和delegatcommand基本上没有啥区别,也是实现了func和action两个参数的办法,基本思路一样。

    它们最大的区别就是在前端的调用方式上。delegatecommand使用了expression的SDK里面的interaction来绑定事件,而这种就是直接通过buttonbase的command属性来绑定,因此只能执行单击事件,所以使用范围比较局限,不过如果用interaction来绑定事件的话,其实实现就和delegatecommand一样了。不过为了总结下学习,还是分开来区别下。

    前端XAML的代码

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

    后台

    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!");
            }

    原文地址:   http://www.cnblogs.com/matoo/archive/2012/04/14/2447159.html

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

  • 相关阅读:
    【咸鱼教程】基于系统时间的计时器DateTimer(不受FPS影响)
    【咸鱼教程】Egret实现摇一摇功能
    【咸鱼教程】可自动滚动的聊天文本框
    【咸鱼教程】虚拟摇杆
    【咸鱼教程】一个简单的画布(阴阳师画符)
    【咸鱼教程】震屏效果
    【咸鱼教程】一个简单的弹出二级菜单UIPopupMenu
    【咸鱼教程】微信网页授权(获取用户头像、昵称等)
    【咸鱼教程】TextureMerger1.6.6 三:Bitmap Font的制作和使用
    【咸鱼教程】TextureMerger1.6.6 二:Sprite Sheet的制作和使用
  • 原文地址:https://www.cnblogs.com/mqxs/p/5713859.html
Copyright © 2011-2022 走看看