Как сделать Button, которая является ItemTemplate для ListBox, получать события клавиатуры? - PullRequest
0 голосов
/ 16 мая 2018

Я создал ListBox и дал ему ItemTemplate, который определен следующим образом:

<DataTemplate x:Key="myDataTemplate">
    <Button Command="{Binding MyListItemButtonCommand}" CommandParameter="{Binding .}">
        <!-- detail omitted -->
    </Button>
</DataTemplate>

Если я нажму на один из элементов списка, он выполнит команду Button, как и ожидалось.Но если я использую навигацию с помощью клавиатуры, чтобы выделить фокус на элементе списка, и нажимаю клавишу Enter или пробел, команда не выполняется.Это связано с тем, что, как описано в этом вопросе , фокусом клавиатуры является элемент списка, а не сама кнопка.Я хочу реагировать на нажатия клавиш, когда элемент списка имеет фокус точно так же, как если бы это была кнопка с фокусом.

Это может быть достигнуто с помощью XAML или с помощью codebehind, но этоне должен требовать от меня определения набора событий, которые мне нужно слушать, и он не должен включать в себя необходимость определять, какие клавиши и комбинации клавиш я должен проверять.Например, решение, содержащее код, подобный if (e.Key == Key.Enter), неприемлемо (поскольку я не хочу отвечать за то, чтобы быть на вершине всех возможных клавиш и комбинаций клавиш, которые могут использоваться для активации встроенного элемента управления кнопки Windows).

Это отличается от связанного вопроса, потому что в этом вопросе спрашивающий написал обработчик события, и им нужна была помощь, чтобы он запустился.Я не написал обработчик событий и не хочу его писать;Я хочу, чтобы кнопка получала события клавиатуры (как если бы это была кнопка с фокусом клавиатуры, а не элемент списка) и отвечала на них, используя обработчики событий, которые являются частью инфраструктуры и уже были написаны для меня кем-тов Microsoft.

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

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

Обычно вы делаете это с помощью ItemsControl, опционально помещаемого в Scrollviewer.

<ItemsControl ...>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Command="{Binding MyListItemButtonCommand}"
                    CommandParameter="{Binding .}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
<ItemsControl>
0 голосов
/ 16 мая 2018

Вы можете обработать событие PreviewKeyDown для контейнера ListBoxItem и программно сфокусировать кнопку:

private void ListBoxItem_PreviewKeyDown(object sender, KeyEventArgs e)
{
    ListBoxItem lbi = (ListBoxItem)sender;
    Button btn = FindVisualChild<Button>(lbi);
    if (btn != null)
        btn.Focus();
}

private static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is T)
            return (T)child;
        else
        {
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}

XAML:

<ListBox ... KeyboardNavigation.TabNavigation="Contained">
    <ListBox.Resources>
        <Style TargetType="ListBoxItem">
            <EventSetter Event="PreviewKeyDown" Handler="ListBoxItem_PreviewKeyDown" />
        </Style>
    </ListBox.Resources>
</ListBox>
...