命令模式簡介及應用

  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。在特定條件下相同的命令需要執行不同的操作時,也可以更改執行函數來達到這種效果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章