2012-09-06 146 views
3

我将焦点移动到其开口弹出:为什么VisualTreeHelper.GetChildrenCount()为Popup返回0?

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类部分:

​​

问题是 VAR计数= VisualTreeHelper .GetChildrenCount(parent)== 0当父级弹出时。

UPDATE

答案是here

回答

9

的弹出窗口不会在其内部承载儿童。相反,它会创建一个PopupRoot(内部类),它是创建的一个新HWND的根目录,用于在单独的顶级窗口(或xbap中的子窗口)内托管弹出窗口的内容。 Popup的子项托管在PopupRoot内的AdornerDecorator中。

3

我对晚会有点迟,但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); 
} 
+0

感谢您的代码! – AbsoluteSith