WPF用户控件检测失去焦点事件时忽略子元素

8
我有一个包含多个元素(ListBoxes、Buttons)和一个带ComboBoxes和Buttons的Popup的UserControl。
我尝试在用户控件上失去焦点,但是每当用户控件内部焦点发生变化时,Lost(Keyboard)Focus事件都会触发。
但我不想知道子级何时失去焦点到UserControl的另一个子级,而是想知道键盘焦点何时移动到UserControl和它的Popup之外的元素。
有没有一种方法可以检测到这一点,而不需要检查每个单独元素的LostFocus?

你能分享一些代码吗?这样更容易纠正你可能犯的错误或解决任何意外问题。也许你应该看一下Control.Leave事件 - Oceans
Control.Leave 是 Windows.Forms 中的一个事件。 - bebo
如果您确实需要创建一个新的WPF控件,最简单的方法是创建一个从UserControl派生的类(...)从UserControl派生是一个适当的模型,如果您想通过向其中添加现有元素来构建控件,就像构建应用程序一样。(如果您想在控件中使用模板,请从Control派生。) - Oceans
2个回答

6

这个解决方案适合您吗?我在UserControl中创建了一个名为LostFocusIgnoreChildren的新事件,仅当新获取焦点的元素不是此UserControl的子元素时才触发。

UserControl1.cs

  public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public event RoutedEventHandler LostFocusIgnoreChildren;
        private void UserControl_LostFocus(object sender, RoutedEventArgs e)
        {
            var focused_element = FocusManager.GetFocusedElement(Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive));
            var parent = (focused_element as FrameworkElement).TryFindParent<UserControl1>();
            if (parent == null && LostFocusIgnoreChildren != null)
                LostFocusIgnoreChildren(this, e);
        }
    }

VisualTreeHelper扩展
 public static class VisualTreeHelperExt
    {
        public static T TryFindParent<T>(this DependencyObject child)
    where T : DependencyObject
        {
            DependencyObject parentObject = GetParentObject(child);
            if (parentObject == null) return null;
            T parent = parentObject as T;
            if (parent != null)
            {
                return parent;
            }
            else
            {
                return TryFindParent<T>(parentObject);
            }
        }

        public static DependencyObject GetParentObject(this DependencyObject child)
        {
            if (child == null) return null;
            ContentElement contentElement = child as ContentElement;
            if (contentElement != null)
            {
                DependencyObject parent = ContentOperations.GetParent(contentElement);
                if (parent != null) return parent;
                FrameworkContentElement fce = contentElement as FrameworkContentElement;
                return fce != null ? fce.Parent : null;
            }
            FrameworkElement frameworkElement = child as FrameworkElement;
            if (frameworkElement != null)
            {
                DependencyObject parent = frameworkElement.Parent;
                if (parent != null) return parent;
            }
            return VisualTreeHelper.GetParent(child);
        }
    }

1
另一种检查给定控件的焦点是否丢失,转而使用其(递归)子控件之一的方法,可以使用此代码示例 - Yoav Feuerstein

1

这样做要容易得多:

private void UserControl_LostFocus(object sender, RoutedEventArgs e)
        {
            if (!this.IsKeyboardFocusWithin)
            {
                _lastFocusedElement = e.OriginalSource as IInputElement;
            }
        }

你的回答可以通过提供更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便其他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community
这实际上是一个更简单和更好的解决方案。解释一些细节:如果你询问你的UserControl "IsKeyboardFocusWithin",它基本上会知道UI对象本身或其UI项当前是否有焦点。对于它的UI对象(也包括其他UserControls),你可以让它调用其父级的方法,这样它也能检测到在同一级别上设置给其他UI对象的焦点。这正是我所寻找的。 - Battle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接