Как я могу запретить элементам управления вводить символ пробела из TextCompositionManager? - PullRequest
4 голосов
/ 28 июня 2009

Связанный (но не обман!) С этим вопросом: Помощь с событиями WPF TextCompositionManager

При использовании TextCompositionManager У меня возникает проблема, при которой, если элемент управления вводом, такой как TextBox, имеет фокус, TextBox будет «красть» символ пробела, прежде чем я получу шанс действовать на это.

Например, у нас есть следующий код:

public Window1()
{
  TextCompositionManager.AddPreviewTextInputStartHandler
    (this, PreviewTextInputStartHandler);
}

private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
  CaptureTextBlock.Text += e.Text;
  e.Handled = true;
}

где Window1 выглядит так:

<!--standard window crap above here-->
<StackPanel>
  <TextBlock Name="CaptureTextBlock" />
  <TextBox Name="ThievingBastard" />
</StackPanel>
<!-- snip -->

Теперь, если я запускаю это приложение и сразу же набираю «Я ненавижу воровских ублюдков», текстовый блок будет содержать текст «Я ненавижу воровских ублюдков», и текстовое поле будет пустым.

Если, однако, я выделю текстовое поле (т. Е. Текстовое поле имеет фокус клавиатуры), после ввода вышеуказанной строки текстовое поле будет содержать текст «Ihaetthivingbastards», а текстовое поле будет содержать текст «» (3 пробела).


У меня есть два вопроса:
1) Могу ли я предотвратить это только с помощью средств, предоставляемых TextCompositionManager?
2) Если нет, то где, черт возьми, я подключаюсь к стеку ввода текста, чтобы я мог полностью контролировать ввод текста в моем приложении WPF (отрицательные моменты даже для того, чтобы думать о p / invoking) (вы только что подумали о это, отрицательные моменты добавлены)?


Обновление

Я использую хакерский обходной путь, когда обрабатываю событие KeyDown туннелирования из InputManager только для пробелов. Этот метод очень неудобен, неэффективен и в основном воняет. Все еще ищу лучший путь.

1 Ответ

6 голосов
/ 02 октября 2009

Для блага других мой хакерский код.

Мое конкретное приложение ожидает считывания карт от кард-ридера. Следующее живет в конструкторе объекта, который следит за пролистыванием карты (это побочный проект; большинство проклятий комментариев отредактировано):

// this is where we handle the space and other keys wpf f*s up.
System.Windows.Input.InputManager.Current.PreNotifyInput += 
    new NotifyInputEventHandler(PreNotifyInput);
// This is where we handle all the rest of the keys
TextCompositionManager.AddPreviewTextInputStartHandler(
    Application.Current.MainWindow, 
    PreviewTextInputHandler);

Два метода:

/// <summary>
/// Handles the PreNotifyInput event of the input manager.
/// </summary>
/// <remarks>Because some controls steal away space (and other) characters, 
/// we need to intercept the space and record it when capturing.</remarks>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The 
/// <see cref="System.Windows.Input.NotifyInputEventArgs"/> 
/// instance containing the event data.</param>
private void PreNotifyInput(object sender, NotifyInputEventArgs e)
{
    // I'm only interested in key down events
    if (e.StagingItem.Input.RoutedEvent != Keyboard.KeyDownEvent)
        return;
    var args = e.StagingItem.Input as KeyEventArgs;
    // I only care about the space key being pressed
    // you might have to check for other characters
    if (args == null || args.Key != Key.Space)
        return;
    // stop event processing here
    args.Handled = true;
    // this is my internal method for handling a keystroke
    HanleKeystroke(" ");
}


/// <summary>
/// This method passes the event to the HandleKeystroke event and turns
/// off tunneling depending on whether or not Capturing is true.
/// Also calls StopCapturing when appropriate.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The 
/// <see cref="System.Windows.Input.TextCompositionEventArgs"/> 
/// instance containing the event data.</param>
private void PreviewTextInputHandler(object sender, 
    TextCompositionEventArgs e)
{
    HanleKeystroke(e.Text);
}

Когда кто-то нажимает клавишу (или нажатие клавиши отправляется в систему), происходит событие PreNotifyInput. В этом случае я определяю, является ли это специальным ключом (мне нужно беспокоиться о пробелах, но другие ключи, очевидно, нуждаются в особом внимании). Если это специальный ключ, я «обрабатываю» событие, останавливая всю дальнейшую обработку этого нажатия клавиши. Затем я вызываю мой метод внутренней обработки, передавая пробел (или любой специальный ключ, который я только что перехватил).

Все остальные ключи обрабатываются методом PreviewTextInputHandler.

В этом коде есть много чего лишнего. Определение того, когда произошло событие свайпа, определение того, когда свайп завершился, удаляются меры предосторожности (тайм-ауты на случай, если я никогда не перестану захватывать свайп), и т. Д. Как вы это сделаете, будет зависеть от ваших требований к коду.

...