Я считаю, что это можно сделать с помощью Reactive Extensions , но я полагаю, что вы подходите к проблеме с неправильной точки зрения.
Вы просматриваете событие KeyPress
как способ получения потока символов. Это неправильно, наблюдаемые события KeyPress
- это просто нажатия клавиш. Да, они соответствуют символам в словах время от времени , но, как вы упомянули, есть нажатия клавиш, которые не имеют ничего общего с символами в словах, кроме других операций.
Тем не менее, вам следует подписаться не на событие KeyPress
, а на TextChanged
событие . Затем ваш IObservable<T>
должен вернуть массив экземпляров строки, соответствующих словам.
Другими словами, вместо того, чтобы передавать нажатия клавиш и пытаться выяснить, какие слова находятся в блоке аддитивным способом, возьмите весь текст в поле и внесите изменения в слова в коробка, на которой вы наблюдаете:
var textChanges = Observable.
FromEventPattern<EventHandler>(textBox, "TextChanged");
// Create an observable that contains the splits.
IObservable<IList<string>> observableWordChanges = textChanges.Select(e => {
// Get the text.
string text = (e.Sender as TextBox).Text;
// The current word.
var word = new StringBuilder();
// The list of words.
IList<string> words = new List<string>();
// Parse.
foreach (char c in text)
{
if (!Char.IsWordSeparator(c))
word.Append(c);
else
{
// Add to the words.
words.Add(word.ToString());
// Clear the builder.
word.Clear();
}
}
// Return the words.
return words;
});
Отсюда вы подписываетесь на изменения слов в виде набора, а не только символов в TextBox
.
Конечно, это немного сложнее в вычислительном отношении, но другой альтернативой является захват всех различных состояний, которые имел бы любое нажатие клавиши , и вы не могли бы получить все из них правильными.
Таким образом, вы будете каждый раз получать слова в поле и сможете корректно сравнивать их с предыдущими словами.
Относительно того, есть ли какая-либо ценность, делающая это, а не просто использование необработанных событий, я бы сказал, да. Два из больших преимуществ использования расширений Reactive:
- Инкапсуляция логики для обработки потоков событий.
- Обрабатывает несколько подписок на один и тот же поток событий.
В этом конкретном примере вы получаете выгоду от обоих.
Вы могли бы выполнить синтаксический анализ набора слов, подключившись к событию TextChanged
, но тогда бы вам пришлось хранить некое состояние в той же структуре, что и обработчик события (в этом В этом случае StringBuilder
) объявляется в. С реактивными расширениями это не потребовалось бы (оно содержится в корпусе).
Кроме того, если вы хотите добавить какое-то дополнительное поведение к обработке потока событий, вам потребуется два вызова в одном обработчике событий или несколько обработчиков событий. С помощью расширений Reactive благодаря лучшей инкапсуляции состояния проще добавлять несколько обработчиков для потока событий к одному и тому же событию в любое время по вашему выбору (в зависимости от того, когда вы подписываетесь).