【问题标题】:Why VisualTreeHelper.GetChildrenCount() returns 0 for Popup?为什么 VisualTreeHelper.GetChildrenCount() 为 Popup 返回 0?
【发布时间】:2012-09-06 16:58:23
【问题描述】:

我将焦点移到弹出窗口的开头:

wcl:FocusHelper.IsFocused="{Binding RelativeSource={RelativeSource Self}, Path=IsOpen}"

FocusHelper 类代码:

public static class FocusHelper
{
     public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusHelper), new FrameworkPropertyMetadata(IsFocusedChanged));

        public static bool? GetIsFocused(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            return (bool?)element.GetValue(IsFocusedProperty);
        }

        public static void SetIsFocused(DependencyObject element, bool? value)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            element.SetValue(IsFocusedProperty, value);
        }

        private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var fe = (FrameworkElement)d;

            if (e.OldValue == null)
            {
                fe.GotFocus += ElementGotFocus;
                fe.LostFocus += ElementLostFocus;
                fe.IsVisibleChanged += ElementIsVisibleChanged;
            }

            if (e.NewValue == null)
            {
                fe.GotFocus -= ElementGotFocus;
                fe.LostFocus -= ElementLostFocus;
                fe.IsVisibleChanged -= ElementIsVisibleChanged;
                return;
            }

            if ((bool)e.NewValue)
            {
                fe.SetFocusWithin();
            }
        }

        private static void ElementIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var fe = (FrameworkElement)sender;

            if (fe.IsVisible 
                && (bool)(((FrameworkElement) sender).GetValue(IsFocusedProperty))) // Bring focus to just become visible element.
                fe.Focus();
        }

        private static void ElementGotFocus(object sender, RoutedEventArgs e)
        {
            ((FrameworkElement)sender).SetCurrentValue(IsFocusedProperty, true);
        }

        private static void ElementLostFocus(object sender, RoutedEventArgs e)
        {
            ((FrameworkElement)sender).SetCurrentValue(IsFocusedProperty, false);
        }

        /// <summary>
        /// Tries to set focus to the element or any other element inside this one.
        /// Tab index is respected
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool SetFocusWithin(this DependencyObject element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            var inputElement = element as IInputElement;
            if (inputElement == null || !inputElement.Focus())
            {
                var children = element.GetVisualChildrenSortedByTabIndex().Where(child => !(child is Control) || (bool)child.GetValue(Control.IsTabStopProperty) );
                return children.Any(SetFocusWithin);
            }

            return true;
        }
    }

ElementTreeHelper 类部分:

public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject parent)
        {
            if (parent == null)
                throw new ArgumentNullException("parent");

            var count = VisualTreeHelper.GetChildrenCount(parent);
            for (var i = 0; i < count; i++)
                yield return VisualTreeHelper.GetChild(parent, i);
        }

        public static IEnumerable<DependencyObject> GetVisualChildrenSortedByTabIndex(this DependencyObject parent)
        {
            if (parent == null)
                throw new ArgumentNullException("parent");

            return parent.GetVisualChildren().OrderBy(KeyboardNavigation.GetTabIndex);
        }

问题是 var count = VisualTreeHelper.GetChildrenCount(parent) == 0 当 parent 是 Popup。

更新

答案是here

【问题讨论】:

    标签: c# wpf popup visualtreehelper visual-tree


    【解决方案1】:

    Popup 本身并不承载 Child。相反,它会创建一个 PopupRoot(内部类),它是新 HWND 的根视觉对象,该 HWND 创建用于在单独的顶级窗口(或 xbap 中的子窗口)中托管弹出窗口的内容。 Popup 的 Child 托管在 PopupRoot 内的 AdornerDecorator 中。

    【讨论】:

      【解决方案2】:

      我参加聚会有点晚了,但 AndrewS 的回答帮助我放弃了在弹出窗口中使用 GetChildrenCount。我确实注意到 Popup 的 Child 属性已正确填充,因此我创建了一个单独的代码路径来查找 Popup 对象的特定子类型。这是我用来按类型(也可以按名称)查找特定子项的代码:

      public static TChildItem FindVisualChild<TChildItem>(this DependencyObject dependencyObject, String name) where TChildItem : DependencyObject
      {
        // Search immediate children first (breadth-first)
        var childrenCount = VisualTreeHelper.GetChildrenCount(dependencyObject);
      
        //http://stackoverflow.com/questions/12304904/why-visualtreehelper-getchildrencount-returns-0-for-popup
        if (childrenCount == 0 && dependencyObject is Popup)
        {
          var popup = dependencyObject as Popup;
          return popup.Child != null ? popup.Child.FindVisualChild<TChildItem>(name) : null;
        }
      
        for (var i = 0; i < childrenCount; i++)
        {
          var child = VisualTreeHelper.GetChild(dependencyObject, i);
          var nameOfChild = child.GetValue(FrameworkElement.NameProperty) as String;
      
          if (child is TChildItem && (name == String.Empty || name == nameOfChild))
            return (TChildItem)child;
          var childOfChild = child.FindVisualChild<TChildItem>(name);
          if (childOfChild != null)
            return childOfChild;
        }
        return null;
      }
      
      public static TChildItem FindVisualChild<TChildItem>(this DependencyObject dependencyObject) where TChildItem : DependencyObject
      {
        return dependencyObject.FindVisualChild<TChildItem>(String.Empty);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-21
        • 2011-03-01
        • 2011-07-01
        • 2011-01-17
        • 2018-04-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多