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

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

上篇文章提到的是屬性(Property)的綁定,這篇開始是針對方法(Method)的綁定實作

要綁定方法用的是 ICommand 這個 WPF 內建的介面

主要要實作出 ICommand 的兩個方法跟一個事件,如下:

  • void Execute(object);
    • 定義叫用命令時要呼叫的方法(要執行的方法)
  • bool CanExecute(object);
    • 定義用來判斷命令是否能以其目前狀態執行的方法(判斷方法是否可以執行)
  • event EventHandler CanExecuteChanged;
    • 發生於影響命令是否應執行的變更發生時(觸發方法的事件)

但不可能每新增一個方法,就重複實作 ICommand 介面,那就衍生出 RelayCommand 這個模組來封裝重複實作的部分

一樣開始新增一個類別,我把它放在 Project 同名的命名空間下

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

namespace MVVM
{
    public class RelayCommand : ICommand
    {
        private readonly Func<bool> _canExecute;
        private readonly Action _execute;

        // 建構子(多型)
        public RelayCommand(Action execute) : this(execute, null)
        {
        }
        // 建構子(傳入參數)
        public RelayCommand(Action execute, Func<bool> 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;
            }
        }
    }
}

這邊我用一個點按鈕跑出訊息框的例子來使用 RelayCommand 類別

首先新增一個範例 ViewModel,加入以下的程式碼

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

    // RelayCommand
    #region command1
    public RelayCommand Command1
    {
        get { return new RelayCommand(command1, CanExecute); }
    }
    private void command1()
    {
        MessageBox.Show("CM1 clicked!");
    }
    #endregion command1
}

然後在 xaml 中,實作按鈕並綁定方法

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

就是這麼簡單完成了!大心~XD