【问题标题】:Where to put events when using MVVM?使用 MVVM 时在哪里放置事件?
【发布时间】:2015-09-19 15:28:47
【问题描述】:

我应该把所有事件都放在视图代码后面还是有更合适的方法,比如在 ViewModel 中放置命令? 例如,我想在 datagrid 行上双击打开 Tab,我应该在哪里处理这个事件?

【问题讨论】:

    标签: wpf mvvm event-handling


    【解决方案1】:

    Kyle 是正确的,您的处理程序应该出现在视图模型中。如果命令属性不存在,那么您可以使用交互触发器:

    <DataGrid>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseDoubleClick">
                <i:InvokeCommandAction Command="{Binding Mode=OneWay, Path=OpenClientCommand}" CommandParameter="{Binding ElementName=searchResults, Path=SelectedItems}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    
        ... other stuff goes here ...
    
    </DataGrid>
    

    或者你可以使用MVVM Lite的EventToCommand,它也可以让你传入消息参数:

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Closing">
            <cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    

    在这种情况下使用哪个来取消窗口关闭事件以响应“您确定要退出吗?”对话:

    public ICommand ClosingCommand { get { return new RelayCommand<CancelEventArgs>(OnClosing); } }
    
    private void OnClosing(CancelEventArgs args)
    {
        if (UserCancelsClose())
            args.Cancel = true;
    }
    

    相关命名空间如下:

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:cmd ="http://www.galasoft.ch/mvvmlight"
    

    【讨论】:

      【解决方案2】:

      不,您不应该将事件放在代码后面。在 MVVM (Model-View-ViewModel) 设计模式中,视图模型是负责处理应用程序的表示逻辑和状态的组件。这意味着您的视图的代码隐藏文件不应包含任何代码来处理从任何用户界面 (UI) 元素引发的事件。

      例如,如果您的 xaml 中有按钮

      <Button Content="OK" Click="btn_Click"/>
      
      protected void btn_Click(object sender, RoutedEventArgs e)
      {
         /* This is not MVVM! */
      }
      

      相反,您可以使用WPF Command。您所要做的就是绑定到它的 Execute 和 CanExecute 委托并调用您的命令。

      所以你的代码现在将是

      public class ViewModel
      {
          private readonly DelegateCommand<string> _clickCommand;
      
          public ViewModel()
          {
               _clickCommand = new DelegateCommand(
              (s) => { /* perform some action */ }, //Execute
              null
          } //CanExecute );
      
          public DelegateCommand ButtonClickCommand
          {
             get { return _clickCommand; }
          }
      }
      
      <Button Content="COOL" Command="ButtonClickCommand"/>
      

      【讨论】:

      • 我已经知道如何使用命令来处理按钮点击事件,但其他事件如行双击等呢?它们没有命令属性。
      • 您也可以对其他控件执行此操作,例如 Datagrid 有 SelectedCellsChanged 事件,您可以使用 SelectedCellsChanged="{Binding YourCommand}" 连接到您的视图模型
      • 我自己正在寻找好的 MVVM 解决方案,但不得不说,当没有针对“正确的”方法。
      • SelectedCellsChanged="{Binding YourCommand}" 给你错误“YourCommand 不是方法。”
      • 好的,但是EventArgs在哪里,如何使用呢?