在 MVVM 中指揮

命令用於在尊重 MVVM 模式的同時處理 WPF 中的 Events

正常的 EventHandler 看起來像這樣(位於 Code-Behind):

public MainWindow()
{
    _dataGrid.CollectionChanged += DataGrid_CollectionChanged;
}

private void DataGrid_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
        //Do what ever
}

不能在 MVVM 中使用 Commands

 <Button Command="{Binding Path=CmdStartExecution}" Content="Start" />

我建議為命令屬性使用某種字首(Cmd),因為你將主要在 xaml 中使用它們 - 這樣它們更容易識別。

因為它是 MVVM,你想要在你的 ViewModel 中處理那個命令(對於 Button``eq``Button_Click)。

為此,我們基本上需要兩件事:

  1. System.Windows.Input.ICommand
  2. RelayCommand(例如從這裡獲取)

一個簡單的例子可能如下所示:

private RelayCommand _commandStart;
public ICommand CmdStartExecution
{
   get
   {
      if(_commandStart == null)
      {
          _commandStart = new RelayCommand(param => Start(), param => CanStart());
      }
      return _commandStart;
   }
}

public void Start()
{
   //Do what ever
}

public bool CanStart()
{
    return (DateTime.Now.DayOfWeek == DayOfWeek.Monday); //Can only click that button on mondays.
}

那麼這個細節是做什麼的:

ICommand 是 xaml 中的 Control 所繫結的。RelayCommand 將你的命令傳送到 Action(即呼叫 Method)。Null-Check 只確保每個 Command 只會初始化一次(由於效能問題)。如果你已經閱讀了上面 RelayCommand 的連結,你可能已經注意到 RelayCommand 對於它的建構函式有兩個過載。(Action<object> execute)(Action<object> execute, Predicate<object> canExecute)

這意味著你可以(通常)新增第二個 Method 返回一個 bool 來告訴 Control whehe事件可以發射或不發射。

一個好處是,如果 Method 將返回 false,例如 Buttons 將是 false

CommandParameters

<DataGrid x:Name="TicketsDataGrid">
    <DataGrid.InputBindings>
        <MouseBinding Gesture="LeftDoubleClick" 
                      Command="{Binding CmdTicketClick}" 
                      CommandParameter="{Binding ElementName=TicketsDataGrid, 
                                                 Path=SelectedItem}" />
    </DataGrid.InputBindings>
<DataGrid />

在這個例子中,我想將 DataGrid.SelectedItem 傳遞給我的 ViewModel 中的 Click_Command。

你的方法應如下所示,而 ICommand 實現本身保持如上所述。

private RelayCommand _commandTicketClick;

public ICommand CmdTicketClick
{
   get
   {
       if(_commandTicketClick == null)
       {
           _commandTicketClick = new RelayCommand(param => HandleUserClick(param));
       }
       return _commandTicketClick;
   }
}

private void HandleUserClick(object item)
{
    MyModelClass selectedItem = item as MyModelClass;
    if (selectedItem != null)
    {
        //Do sth. with that item
    }
}