使用MVVM时放置事件的位置?

Mrg*_*Gek 8 wpf event-handling mvvm

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

Roh*_*hit 8

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

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

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

相反,您可以使用WPF命令。您所要做的就是绑定到其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; }
    }
}
Run Code Online (Sandbox Code Playgroud)
<Button Content="COOL" Command="ButtonClickCommand"/>
Run Code Online (Sandbox Code Playgroud)

  • 我已经知道如何对按钮单击事件使用命令,但是其他事件(如行双击等)呢?他们没有命令属性。 (6认同)
  • 我自己正在寻找好的 MVVM 解决方案,但不得不说,当没有“正确”方法的开箱即用解决方案时,很难证明“不要将东西放在代码后面”。 (2认同)
  • 好的,但是`EventArgs`在哪里,如何使用它们呢? (2认同)

Mar*_*man 5

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>
Run Code Online (Sandbox Code Playgroud)

或者您可以使用MVVM Lite的EventToCommand,它还允许您传递消息参数:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Closing">
        <cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
    </i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,用于取消窗口关闭事件以响应"你确定要退出吗?" 对话:

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

相关名称空间如下:

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:cmd ="http://www.galasoft.ch/mvvmlight"
Run Code Online (Sandbox Code Playgroud)