我将焦点转移到Popup的开头:
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当父级是Popup时。
更新
答案是here
答案 0 :(得分:9)
Popup本身不会托管Child。相反,它创建一个PopupRoot(内部类),它是创建的新HWND的根视觉,用于在单独的顶级窗口(或xbap中的子窗口)中托管弹出窗口的内容。 Popup的子项托管在该PopupRoot中的AdornerDecorator中。
答案 1 :(得分: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);
}