Почему UIElement.MoveFocus() не перемещает фокус на следующий родственный элемент в ListBox?

У меня есть следующее визуальное дерево:

<DockPanel>
    <TextBox Name="ElementWithFocus" DockPanel.Dock="Left" />
    <ListBox DockPanel.Dock="Left" Width="200" KeyUp="handleListBoxKeyUp">
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
    </ListBox>
    <TextBox DockPanel.Dock="Left" />
</DockPanel>

handleListBoxKeyUp это следующее:

private void handleListBoxKeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        ((UIElement)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }
}

Когда ListBox имеет фокус клавиатуры (на самом деле, я думаю, ListBoxItem), нажатие Enter перемещает фокус на первый элемент в ListBox, а не на следующий TextBox. Почему это происходит и как заставить клавишу Enter действовать как Tab здесь?


person codekaizen    schedule 02.01.2013    source источник


Ответы (2)


Вместо того, чтобы вызывать MoveFocus для отправителя, вы должны вызывать его для исходного источника, найденного в аргументах события.

Параметр sender всегда будет самим ListBox, а вызов MoveFocus для этого с FocusNavigationDirection.Next перейдет к следующему элементу управления в дереве, который является первым ListBoxItem.

Исходным источником маршрутизируемого события будет выбранный ListBoxItem, а следующим за ним элементом управления будет TextBox, на который вы хотите получить фокус.

((UIElement)e.OriginalSource).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
person Peter Hansen    schedule 02.01.2013
comment
Возможно, вы можете сказать мне, почему WPF считает, что следующий элемент управления после ListBoxItem не является просто следующим родственным элементом ListBoxItem? - person codekaizen; 03.01.2013
comment
Если вы используете FocusNavigationDirection.Down или FocusNavigationDirection.Up вместо Next, фокус будет перемещаться вверх/вниз по ListBoxItems. Next, похоже, нажимает на следующий элемент управления, который не находится на том же уровне, что и источник. - person Peter Hansen; 03.01.2013
comment
@codekaizen Next/Previous похож на Tab/Shift-Tab, которые в ListBox не используются для навигации между элементами. - person AndrewS; 03.01.2013

Другим методом, позволяющим получить код для перехода к следующему текстовому полю, является создание события вкладки вручную. Замена вашего кода внутри оператора if следующим сработала для меня:

KeyEventArgs args = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Tab);
args.RoutedEvent = Keyboard.KeyDownEvent;
InputManager.Current.ProcessInput(args);
person Josh    schedule 02.01.2013
comment
Я думал об этом, но обычно мне не нравится заменять ввод, поскольку это может вызвать непреднамеренные побочные эффекты с входными фильтрами, такими как адаптивные программы чтения с экрана. - person codekaizen; 03.01.2013