Я пытаюсь реализовать простую функцию автозамены в WPF RichTextBox.В частности, две функции: 1.) расширение аббревиатуры (когда вы вводите «idk» и пробел, «idk» заменяется на «я не знаю») и 2.) добавление точки в концелиния.Я реализую это через событие PreviewKeyDown, определяя, когда происходит разделитель слов (для расширения аббревиатуры) или возврат каретки (для добавления точки).Это работает по большей части, но я вижу странное поведение при наборе очень быстро.Кажется, что вставка символа в текст может произойти после события PreviewKeyDown для последующего ключа.
Например, предполагается, что вы хотите ввести аббревиатуру "idk" с последующим возвратом каретки, так что в итоге вы получите строку "Я не знаю".Если вы введете «id», а затем «k» и «[ENTER]» в быстрой последовательности, событие PreviewKeyDown для клавиши [ENTER] наступает за до , когда «k» вставляется в текст.Таким образом, код события PreviewKeyDown не видит полную сокращенную аббревиатуру «idk» - он просто видит «id».И затем он ставит точку в конце «id» (из-за клавиши [ENTER]).Наконец, после этого в текст вставляется буква «k», и в результате получается «id.k»
. Это очень необычный случай.Если вы не нажимаете клавиши «k» и [ENTER] почти одновременно, это не происходит.У меня есть демо-приложение, в котором я использую библиотеку имитатора ключей WPF для отправки символов сразу после друг друга.Приложение здесь: https://github.com/garzooma/RichTextBoxDemo. Библиотека имитатора ключей здесь https://archive.codeplex.com/?p=wpfsendkeys].
Я пытался установить флаги, чтобы задержать обработку второго нажатия клавиши, но это просто все зависает- 1-е нажатие клавиши никогда не обрабатывается.
В моем демонстрационном приложении я пытаюсь взломать, когда код обнаруживает, когда символ не был обработан до того, как произойдет последующее нажатие клавиши, установив флаг в PreviewTextInputобработчик событий и очистка его в обработчике TextChanged.Когда код PreviewKeyDown видит флаг, я устанавливаю переменную Action, которая обрабатывается в последующем событии TextChanged.Это похоже на работу.Но я надеюсь найти способ, чтобы проблема не возникала.
Основной код:
private void PreviewKeyDownHandler(object sender, KeyEventArgs e)
{
// See if we're at the end of a word
if (delimiterKeys.Contains(e.Key))
{
string word = GetPrecedingText();
// Is the word an abbreviation?
if (abbreviations.ContainsKey(word.ToUpper()))
{
TextPointer pointer = textbox1.CaretPosition.GetPositionAtOffset(-word.Length);
if (pointer.LogicalDirection == LogicalDirection.Backward) // change direction, if needed
{
pointer = pointer.GetPositionAtOffset(0, LogicalDirection.Forward);
textbox1.CaretPosition = pointer;
}
// replace abbreviation w/expansion
pointer.DeleteTextInRun(word.Length);
pointer.InsertTextInRun(abbreviations[word.ToUpper()]);
}
// Are we at the end of a line, and don't have a period?
if (e.Key == Key.Enter && !word.EndsWith("."))
{
TextPointer pointer = textbox1.CaretPosition;
if (pointer.LogicalDirection == LogicalDirection.Backward) // change direction, if needed
{
pointer = pointer.GetPositionAtOffset(0, LogicalDirection.Forward);
textbox1.CaretPosition = pointer;
}
pointer.InsertTextInRun(".");
}
}