WPF DatePicker LostFocus触发七次

本文关键字:七次 DatePicker LostFocus WPF | 更新日期: 2023-09-27 18:16:34

我这里有一个非常简单的场景。请看一下布局:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <TextBox Grid.Row="0"></TextBox>
    <DatePicker Grid.Row="1" 
                Name="_datePicker"
                LostFocus="_datePicker_OnLostFocus"></DatePicker>
</Grid>
后台代码:

private void _datePicker_OnLostFocus(object sender, RoutedEventArgs e)
{
    Debug.WriteLine("LostFocuse");
}

所以,问题是当我拿起一些日期并单击TextBox时,事件LostFocus触发7次( 7 !)。有一次DatePicker真的失去了焦点,当我点击TextBox时,剩下的六次完全无法解释。

我该如何修复它?我只需要一个触发此事件。或者我可以用其他事件?我尝试了LostKeyBoardFocus与相同的结果。

WPF DatePicker LostFocus触发七次

LostFocus是路由策略设置为 Bubble 的路由事件。冒泡意味着它将冒泡到父窗口直到根窗口,直到通过显式设置 e.Handled = true; 在某处处理。

所以,这意味着即使当子控件失去焦点时它也会冒泡到你的datePicker上这就是为什么你会看到多个点击到你的方法

您可以检查属性 IsKeyboardFocusWithin ,如果焦点在您的控制范围内,则返回。由于您对侦听子丢失焦点事件不感兴趣,您可以像这样检查处理程序中的此属性,并仅在实际焦点被datePicker丢失时执行代码:

private void _datePicker_OnLostFocus(object sender, RoutedEventArgs e)
{
    DatePicker picker = sender as DatePicker;
    if (!picker.IsKeyboardFocusWithin)
    {
        System.Diagnostics.Debug.WriteLine("LostFocuse");
    }
}

您可以添加一个bool值用于第一次检查,然后将e.Handled设置为true。

bool isFired = false;
private void _datePicker_OnLostFocus(object sender, RoutedEventArgs e)
{
    if (!isFired)
        {
            isFired = true;
        }
        e.Handled = true;
}

您已经描述了UIElement.LostFocus事件的正常. net行为。从MSDN上的链接页面:

当此元素失去逻辑焦点时发生。

注意它说logical focus…WPF有两种焦点;逻辑和键盘。再次从链接页面:

逻辑焦点与键盘焦点不同,如果焦点是通过使用方法调用故意强制转移的,但之前的键盘焦点存在于不同的作用域中。在这个场景中,键盘焦点保持在原来的位置,而调用focus方法的元素仍然获得逻辑焦点。

最后,为什么事件被提出了这么多次?这是因为即使是DatePicker中的子元素也可以在单击它们时从中移除逻辑焦点,并且当焦点通过各种内部控制移动时,它可以快速连续多次返回DatePicker。再一次,从链接页面:

因为该事件使用冒泡路由,所以失去焦点的元素可能是一个子元素,而不是实际附加了事件处理程序的元素。