.net 从整体上识别DataGrid的失焦事件,而不是其控件失焦 目标:

.net 从整体上识别DataGrid的失焦事件,而不是其控件失焦 目标:,.net,wpf,mvvm,datagrid,mvvm-light,.net,Wpf,Mvvm,Datagrid,Mvvm Light,我有一个WPF/MVVM(确切地说是MVVM light)应用程序,我想在其中识别/捕获datagid的lostfocus事件作为一个整体,并将其绑定到视图模型中的ICommand 问题在于,每当datagrid中的控件失去焦点以及datagrid本身失去焦点时,就会触发失去焦点事件。在我的应用程序中,如果viewModle“HasErrors”属性为true,则如果用户试图从当前视图“导航”,我会在datagrid lostfocus事件/命令上抛出警告(MVVM类型的消息框)。结果是,即使用

我有一个WPF/MVVM(确切地说是MVVM light)应用程序,我想在其中识别/捕获datagid的lostfocus事件作为一个整体,并将其绑定到视图模型中的ICommand

问题在于,每当datagrid中的控件失去焦点以及datagrid本身失去焦点时,就会触发失去焦点事件。在我的应用程序中,如果viewModle“HasErrors”属性为true,则如果用户试图从当前视图“导航”,我会在datagrid lostfocus事件/命令上抛出警告(MVVM类型的消息框)。结果是,即使用户在datagrid中的控件之间移动,用户也会收到此错误/警告。我只想在datagrid作为一个整体失去焦点时使用它

是什么让这变得困难: 简单地说,使用MVVM是困难的。通常,您可以在lostfocus事件背后的代码中检查FocusManager,以获取当前聚焦的元素,并查看其是否在datagrid()中

问题: 这个问题有MVVM标准解决方案吗?我并不是盲目地死硬地要求MVVM永远不要有代码落后,我想我只是想知道这是不是其中的一次,或者是否有一些策略。我没有想到的选项,这是可能的

我的尝试: 首先-我尝试为不同的命令设置不同的命令参数。即:

<DataGrid>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="LostFocus">
            <cmd:EventToCommand Command="{Binding DataContext.PreNavigateValidateCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
            CommandParameter="DataGridLostFocus"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</DataGrid>

以及datagrid中的控件

<DataGrid>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="LostFocus">
            <cmd:EventToCommand Command="{Binding DataContext.LostFocusValidateCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
             CommandParameter="ControlostFocus"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</DataGrid>

请注意DataGridLostFocus和ControlLostFocus命令参数的差异。但实际情况是,这些命令只发生两次,每个命令参数一次,首先发生控件lostfocus,然后是datadrid lostfocus

-您将注意到不同的命令属性/名称。即使将命令绑定到不同的命令对象也不能解决这个问题。将按上述相同顺序调用这两个命令

第三个数据网格位于网格内,网格位于扩展器内,扩展器位于用户控件内。我试着移动ICommand触发器,将可视化树绑定到这三个元素。即使放置在这三个“父”对象中的任何一个上,丢失焦点事件也会以相同的方式激发


我开始认为我需要找到另一个可以工作的事件,或者完全重新考虑如何处理viewmodels的HasErrors属性的错误触发器

如果能帮助隔离datagrid的失焦事件,我将不胜感激,因为它仍然遵循MVVM标准


谢谢

我认为我们大多数开发人员(包括我自己)长期以来都对MVVM有着广泛的误解

这导致了无需的过度复杂,因为我们倾向于完全避免代码落后,没有真正理解如果我们不在视图层中放置任何代码/逻辑,就不会有绑定、转换器、相对资源、XAML

MVVM的真正精神是
逻辑与UI分离,而不是避免视图中出现任何代码

这确实意味着您可以而且应该通过代码隐藏来解决
焦点
问题(顺便说一句,这纯粹是一个视图问题)。 但是,这并不意味着您将在代码中放置任何应用程序/业务逻辑

简单地说,只需在代码隐藏中处理任何UI事件,然后将逻辑委托给ViewModel:

private void DataGrid_LostFocus(object sender, RoutedEventArgs e)
{
    if (DataGrid.IsKeyboardFocusWithin) //or whatever UI condition
    {
        //Resolve the ViewModel via DI, constructor injection or whatever. Then:
        ViewModel.DoMyBusinessLogic();
    }
}
明白我的意思吗?您没有将业务逻辑放在这里。业务逻辑仍在ViewModel/模型中,而与视图相关的代码(
焦点
)则放在代码后面

而且,这正是
命令所做的。它们对视图中的某个事件做出反应,然后调用视图模型中的某个方法,不是吗

我认为这将真正缓解我们习惯的严格的无代码隐藏政策所带来的痛苦


我也想听听其他人对此的看法

谢谢。这是一个非常清晰的解释,说明了如何“在代码隐藏中处理任何UI事件,然后将逻辑委托给ViewModel”。我是这样学习的,但我的解决方案没有那么干净,我正在寻找一些社区反馈。我知道这是一个常见的话题/误解,我同意我们可以把事情复杂化。我自己太专注于通过对ViewModel属性的严格绑定来完成所有事情。尽管如此,我仍然觉得MVVM方法总体上促使我编写更好的、更易于维护和测试的代码。我认为有趣的是,我的经验是,MVVM没有公认的“最佳实践”。甚至MVVM的框架都是新的,并且得到了较小社区的支持(prism除外,prism是另一条陡峭的学习曲线)。我对MVVM有一条陡峭的学习曲线,因为我发现了很多关于如何使用MVVM的不同文档,而且很多文档都已经存在多年了。即使是声称使用MVVM编写了VisualStudio2012大部分内容的微软也没有明确记录其最佳实践。至少我能找到什么。我希望随着MVVM的成熟,这会有所改进。@HighCode只是一句精彩的话。每一种方法或最佳实践都应该合理地采用,否则就会沦为货物崇拜