使用 MVVM 时将事件放在哪里?
Where to put events when using MVVM?
我应该将所有事件放在视图代码后面,还是有更合适的方法,比如在 ViewModel 中放置命令?
例如,我想在双击 datagrid 行时打开 Tab,我应该在哪里处理这个事件?
不,您不应该将事件放在代码后面。在 MVVM(模型-视图-视图模型)设计模式中,视图模型是负责处理应用程序的呈现逻辑和状态的组件。这意味着您的视图的代码隐藏文件不应包含任何代码来处理从任何用户界面 (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"/>
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>
在这种情况下用于取消响应 "Are you sure you want to quit?" 对话框的 window 关闭事件:
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"
我应该将所有事件放在视图代码后面,还是有更合适的方法,比如在 ViewModel 中放置命令? 例如,我想在双击 datagrid 行时打开 Tab,我应该在哪里处理这个事件?
不,您不应该将事件放在代码后面。在 MVVM(模型-视图-视图模型)设计模式中,视图模型是负责处理应用程序的呈现逻辑和状态的组件。这意味着您的视图的代码隐藏文件不应包含任何代码来处理从任何用户界面 (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"/>
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>
在这种情况下用于取消响应 "Are you sure you want to quit?" 对话框的 window 关闭事件:
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"