WPF: OnKeyDown() не вызывается для пробела в управлении, полученном из WPF TextBox

В приложении WPF у меня есть элемент управления, который я получил из TextBox следующим образом:

public class SelectableTextBlock : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        e.Handled = false;
    }
}

Метод OnKeyDown не вызывается при вводе пробела в TextBox и при нажатии Backspace, но срабатывает для другого ввода, включая обычные печатные символы (например, "a" ) и клавиши-модификаторы (например,).

Я использую этот элемент управления с IsReadOnly, установленным в true, чтобы я мог отображать выбираемый, неизменяемый текст. Элемент управления, используемый в WPFoolkit DataGrid, и я хочу, чтобы события KeyDown распространялись по сетке данных, даже если в SelectableTextBlock есть фокус, поэтому я использую настраиваемый элемент управления, чтобы явно отмечать событие как необработанное.

Проблема в том, что это событие даже не позволяет мне управлять некоторыми ключами. Я не могу просто использовать OnPreviewKeyDown в DataGrid, чтобы обойти это, так как я хочу, чтобы другие элементы управления, используемые в сетке данных, проглотили пробел KeyDown.

Кто-нибудь знает, как я могу получить событие KeyDown для распространения пробела?

Спасибо.

Ответы

Ответ 1

Похоже, проблема заключается в том, что событие key (и backspace и т.д.) с ключевыми словами обрабатывается уже внутри TextBox, прежде чем оно превратится в мой производный элемент управления. Я предполагаю, что это часть процесса составления текста, как опубликовал Wim.

Чтобы обойти это, я добавил обработчик, который получит событие с нажатием клавиши, даже если оно уже обработано, и устанавливает его обработанный элемент равным false, чтобы он мог нормально функционировать. В приведенном ниже примере он просто делает это для ключей пространства, но в моем случае мне нужно сделать это для любых ключевых событий, которые я действительно не хочу обрабатывать в своем SelectedableTextBlock, так как я не знаю, какие ключевые события родители могут быть заинтересованы в еще.

public class SelectableTextBlock : TextBox
{
    public SelectableTextBlock() : base()
    {
        this.AddHandler(SelectableTextBlock.KeyDownEvent, new RoutedEventHandler(HandleHandledKeyDown), true);
    }

    public void HandleHandledKeyDown(object sender, RoutedEventArgs e)
    {
        KeyEventArgs ke = e as KeyEventArgs;
        if (ke.Key == Key.Space)
        {
            ke.Handled = false;
        }
    }
    ...
}

Мне, конечно, все равно интересно, есть ли у кого-то лучшее решение...

Спасибо, Е.

Ответ 2

Событие PreviewKeyDown существует именно для такого рода вещей.

private void spacebarHandler_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Space)
        e.Handled = true;
}

Ваш обработчик KeyDown никогда не получит событие KeyDown для пробела.

Ответ 3

У меня была проблема с пробелами и событиями один раз в текстовом поле. Не активируются ли события НЕ только при добавлении или удалении символа пробела?

Вот что я получил в качестве ответа: (http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/446ec083-04c8-43f2-89dc-1e2521a31f6b)

Поскольку некоторые IME будут обрабатывать пробельные нажатия клавиш как часть процесса составления текста, то почему он ловит Avalon для сообщения правильного композитного текста через событие TextInput.

Я мог быть полностью вне сферы действия, но, читая эту нить, emmideatly заставил меня подумать об этой проблеме, которую я когда-то имел.

С уважением, Wim

Ответ 4

Выведите слово: RestrictKeysTextBox из TextBox.

public class RestrictKeysTextBox : TextBox
{
    ....
}

Переопределить событие OnPreviewKeyDown в RestrictKeysTextBox.

Поместите логику в это переопределение следующим образом:

if (e.Key == Key.Space)
{
    e.Handled = true;
}

Привяжите экземпляр RestrictKeysTextBox к вашему DataGrid.

Это должно работать без переопределения OnPreviewKeyDown в DataGrid и устранения связанных проблем.