[WPF] MVVM 軟體架構模式 - 透過 RelayCommand 綁定方法 (泛型參數)

透過 RelayCommand 綁定方法 (泛型參數)

雖然已經實作一版 RelayCommand 來綁定方法,但如果要傳入參數的話,原先的 Relay Command 明顯是做不到的!

那我們就改動一下 RelayCommand 來接受泛型參數輸入,另外加上泛型類型條件約束(Generic Type Constraint)限制 T 為參考型別

一樣新增個類別,改成以下的內容(如果要同時保留兩個版本,那就把類別名改一下吧~別忘了建構子也要變唷~XD)

using System;
using System.Diagnostics;
using System.Windows.Input;

namespace MVVM
{
    public class RelayCommand<T> : ICommand where T : class
    {
        private readonly Predicate<T> _canExecute;
        private readonly Action<T> _execute;

        // 建構子(多型)
        public RelayCommand(Action<T> execute, object canExecute) : this(execute, null)
        {
        }
        // 建構子(傳入參數)
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            // 簡化寫法 if(execute == null) throw new ArgumentNullException("execute");
            _execute = execute ?? throw new ArgumentNullException("execute");
            _canExecute = canExecute;
        }

        #region -- ICommand Members --
        // 當_canExecute發生變更時,加入或是移除Action觸發事件
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null) CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null) CommandManager.RequerySuggested -= value;
            }
        }

        public void RaiseCanExecuteChange()
        {
            CommandManager.InvalidateRequerySuggested();
        }

        // 下面兩個方法是提供給 View 使用的
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            // return _canExecute == null ? true : _canExecute();
            if (_canExecute == null) return true;
            return _canExecute((T)parameter);
        }

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

熊熊一看,除了參數部分,委託也從 Func<bool> 改成 Predicate<T>,這差別只在預設回傳值差別,要寫成 Func<T, bool> 也是可以的

另外就是 CanExecute 內的判斷式,我從原本的三元運算子 ?: 改成用 if 判斷(練習一下兩者的寫法),其實都一樣的 XD

以下就用這個可以傳泛型參數的 RelayCommand 來實作一下

新增個 ViewModel 類別並加入以下程式碼

public class TestViewModels : ViewModelBase
{
    private bool CanExecut(object param)
    {
        return true;  // 假設都執行
    }

    // Generic RelayCommand
    #region command1
    public RelayCommand<object> Command1
    {
        get { return new RelayCommand(command1, CanExecute); }
    }
    private void command1(object param)
    {
        string msg = param as string;

        if (msg == "getCMD")
            MessageBox.Show("Get params!");
    }
    #endregion command1
}

在 xaml 部分則是加入以下按鈕跟屬性,多增加了 CommandParameter 輸入參數值

<Button x:Name="BTN_CN1" Command="{Binding Command1} CommandParameter="getCMD"/>

上面範例就是按下按鈕,輸入參數,判斷輸入參數值跟條件字串一樣就顯示訊息視窗~

一樣簡單收尾,打完收工!XD