WPF, Події введення з клавіатури

WPF --- Основа WPF --- Події введення з клавіатури

Коли користувач натискає клавішу, з'являється ціла серія подій. У таблиці ці події перераховані у порядку їх виникнення:

Обробка подій клавіатури аж ніяк не така легка, як це може здатися. Деякі елементи керування можуть блокувати частину цих подій, щоб виконувати власну обробку клавіатури. Найбільш яскравим прикладом є елемент TextBox, який блокує подію TextInput, а також подію KeyDown для натискання деяких клавіш, таких як клавіші керування курсором. У подібних випадках зазвичай все-таки можна використовувати події, що тунелюються (PreviewTextlnput і PreviewKeyDown).

Елемент TextBox додає одну нову подію – TextChanged. Ця подія виникає відразу після того, як натискання кнопки призводить до зміни тексту в текстовому полі. Однак у цей момент новий текст вже бачимо в текстовому полі, тому скасовувати небажане натискання клавіші вже пізно.

Обробка натискання кнопки

Зрозуміти, як працюють та використовуються події клавіатури, найкраще на прикладі. Нижче наведено приклад програми, яка відстежує та протоколює всі можливі натискання клавіш, коли у фокусі знаходиться текстове поле. У цьому випадку показаний результат введення великої літери S.

Цей приклад демонструє важливий момент. Події PreviewKeyDown та KeyDown виникають при кожному натисканні клавіші. Однак подія TextInput виникає лише тоді, коли в елементі було "введено" символ. Насправді це може означати натискання багатьох кнопок. У прикладі, потрібно натиснути дві клавіші, щоб отримати велику букву S: спочатку клавішу , а потім клавішу . В результаті виходять дві події KeyDown і KeyUp, але тільки одна подіяTextInput.

Кожна з подій PreviewKeyDown, KeyDown, PreviewKey та KeyUp передає об'єкту KeyEventArgs одну й ту саму інформацію. Найважливішою її частиною є властивість Key, яка повертає значення з переліку System.Windows.Input.Key та ідентифікує натиснуту або відпущену клавішу.

Значення Key не враховує стан будь-якої іншої клавіші, наприклад, чи була притиснута клавіша в момент натискання ; у будь-якому випадку ви отримаєте те саме значення Key (Key.S).

Тут є одна складність. Залежно від налаштування клавіатури у Windows, утримання клавіші в притиснутому стані призводить до повтору натискання після короткого проміжку часу. Наприклад, притискання клавіші призведе до введення в текстове поле цілої серії символів S. Так само притискання клавіші призводить до повторів натискання та виникнення серії подій KeyDown. У реальному прикладі при натисканні комбінації текстове поле згенерує серію подій KeyDown для клавіші , потім подію KeyDown для клавіші , подію TextInput (або подію TextChanged у випадку текстового поля), а потім подію KeyUp для клавіш і . Якщо потрібно ігнорувати повтори натискання клавіші, можна перевірити, чи є натискання результатом притискання клавіші, за допомогою властивості KeyEventArgs.IsRepeat.

Події PreviewKeyDown, KeyDown, PreviewKey і KeyUp більше підходять для написання низькорівневого коду обробки введення з клавіатури (що рідко буває потрібно — хіба що в елементах керування) і обробки натискань спеціальних клавіш (наприклад, функціональних).

За подією KeyDown слідує подія PreviewTextInput. (Подія TextInput не виникає, оскільки елемент TextBox блокує його.) У цей момент текст ще не відображається в елементі керування.

Подія TextInputзабезпечує код об'єкта TextCompositionEventArgs. Цей об'єкт містить властивість Text, що дає оброблений текст, підготовлений до передачі елементу керування.

В ідеалі подію PreviewTextInput можна було б використовувати для перевірки в елементах управління на кшталт TextBox. Наприклад, якщо ви створюєте текстове поле для введення лише чисел, можна перевірити, чи не була введена при поточному натисканні клавіша буква, і встановити прапорець Handled, якщо це так. На жаль, подія PreviewTextIlnput не генерується для деяких клавіш, які буває потрібно обробляти. Наприклад, при натисканні клавіші пробілу в текстовому полі подія PreviewTextInput взагалі пропускається. Це означає, що доведеться обробляти подію PreviewKeyDown.

На жаль, важко реалізувати надійну логіку перевірки даних у обробнику події PreviewKeyDown, т.к. є лише значення Key, а це занадто низькорівневий фрагмент інформації. Наприклад, у переліку Key розрізняються клавіші цифрової клавіатури (блок, призначений для введення лише цифр) та звичайної клавіатури. Це означає, що в залежності від того, де натиснуто клавішу з цифрою 9, ви отримаєте або значення Key.D9, або значення Key.NumPad9. Перевірка всіх допустимих значень, як мінімум, дуже втомлива.

Одним із виходів є використання класуKeyConverter, який дозволяє перетворити значення Key на більш корисний рядок. Наприклад, виклик функції KeyConverter.ConvertToString() з будь-яким із значень Key.D9 та Key.NumPad9 повертає рядковий результат "9". Виклик перетворення Key.ToString() дає менш корисне ім'я перерахування (або "D9", або "NumPad9"):

Однак використовувати KeyConverter теж не дуже зручно, оскільки доводиться обробляти довгі рядки (наприклад,"Backspace") для тих натискань клавіш, які не призводять до введення тексту.

Найбільш підходящим варіантом є обробка події PreviewTextlnput (де виконується більша частина перевірки) у поєднанні з подією PreviewKeyDown для натискання тих клавіш, які не генерують подію PreviewTextInput в текстовому полі (наприклад, пробілу).