I move focus to the Popup on its opening:
wcl:FocusHelper.IsFocused="{Binding RelativeSource={RelativeSource Self}, Path=IsOpen}"
FocusHelper class code:
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 class part :
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);
}
The problem is that var count = VisualTreeHelper.GetChildrenCount(parent) == 0 when parent is Popup.
UPDATE
The answer is here
The Popup doesn't host the Child within itself. Instead it creates a PopupRoot (internal class) that is the root visual of a new HWND created to host the popup's content within a separate top level window (or child window in xbap). The Child of the Popup is hosted within an AdornerDecorator within that PopupRoot.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With