命令模式简介及应用

  Mvvm中为了实现UI和业务模块的解耦,为每个UI量身定制了一个ViewMoel,两者的交互往往通过绑定进行,数据交互直接绑定数据即可,而业务交互则依靠命令绑定。命令绑定用到了设计模式中的命令模式,命令模式简单的说就是将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。关于命令模式更多内容请点击http://baike.baidu.com/view/1963264.htm#6.
  Wp&Win8中命令模式是依靠ICommand接口实现的:
    public interface ICommand
    {
        // 摘要:
        //     当出现影响是否应执行该命令的更改时发生。
        event EventHandler CanExecuteChanged;

        // 摘要:
        //     定义用于确定此命令是否可以在其当前状态下执行的方法。
        //
        // 参数:
        //   parameter:
        //     此命令使用的数据。如果此命令不需要传递数据,则该对象可以设置为 null。
        //
        // 返回结果:
        //     如果此命令可以执行,则为 true;否则为 false。
        bool CanExecute(object parameter);
        //
        // 摘要:
        //     定义在调用此命令时调用的方法。
        //
        // 参数:
        //   parameter:
        //     此命令使用的数据。如果此命令不需要传递数据,则该对象可以设置为 null。
        void Execute(object parameter);
    }
   关于此接口的实现网上可以找到很多的示例,最初看到有人把每个命令都单独封装成了一个类,个人感觉这样实现起来麻烦不说,而且灵活性也很差。后来找到了一种比较好的实现方法介绍给大家。
 /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T">执行函数的参数类型</typeparam>
    public interface IActionCommand<T> : ICommand
    {        
        /// <summary>
        /// 设置执行函数
        /// </summary>
        /// <param name="action"></param>
        void SetAction(Action<T> action);

        /// <summary>
        /// 设置确定此命令是否可以在其当前状态下执行的方法
        /// </summary>
        /// <param name="canExecute"></param>
        void SetCanExecute(Func<T, bool> canExecute);

        /// <summary>
        /// 执行函数改变时发生
        /// </summary>
        event EventHandler ActionChanged;   
    }
  以上是命令模式通用接口,新增2个函数和一个事件。每个命令的执行方法和当前可执行方法都可以改变,改变时会触发相应的事件。
  以下是接口的具体实现:
    public class ActionCommand<T> : IActionCommand<T>
    {
        private Action<T> _execute = obj => { };
        private Func<T,bool> _canExecute = obj => true;

        public event EventHandler CanExecuteChanged;
        public event EventHandler ActionChanged;

        public ActionCommand()
        {
            
        }

        public ActionCommand(Action<T> execute)
        {
            _execute = execute;
        }

        public ActionCommand(Action<T> execute, Func<T, bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public void SetAction(Action<T> action)
        {
            _execute = action;
            var handler = ActionChanged;
            if(handler!=null)
                handler(this, EventArgs.Empty);
        }

        public void SetCanExecute(Func<T, bool> canExecute)
        {
            _canExecute = canExecute;
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute((T) parameter);
        }

        public void Execute(object parameter)
        {
            if (CanExecute(parameter))
            {
                _execute((T) parameter);
            }
        }
    }
  使用如下:
 public class ViewModel
    {
        public ActionCommand<object> FunCommand { get; private set; }

        void Fun(object parameter)
        {

        }

        public ViewModel()
        {
            InitializeData();
        }

        protected override void InitializeData()
        {
            FunCommand = new ActionCommand<object>(Fun);
        }
    }
  在Xaml中使用如下:
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding GetSourceCommand}" CommandParameter="123"/>  
        </i:EventTrigger>
    </i:Interaction.Triggers>
  一个ViewModel中可以有多个Command。在特定条件下相同的命令需要执行不同的操作时,也可以更改执行函数来达到这种效果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章