Упражнение 1. Обработка событий клавиатуры
При нажатии клавиши пользователем, когда элемент имеет фокус, возникает несколько событий, которые определены в классе UIElement и в порядке их возбуждения приведены в таблице
События клавиатурного ввода | ||
Событие | Стратегия маршрутизации | Описание |
PreviewKeyDown | Tunnel | Происходит при нажатии |
KeyDown | Bubble | Происходит при нажатии |
PreviewTextInput | Tunnel | Происходит для символьных клавиш, когда нажатие завершено и элемент получил символ |
TextInput | Bubble | Происходит для символьных клавиш, когда нажатие завершено и элемент получил символ |
PreviewKeyUp | Tunnel | Происходит при отпускании |
KeyUp | Bubble | Происходит при отпускании |
Некоторые элементы сами обрабатывают часть этих событий. Они могут блокировать дальнейшее продвижение некоторых из них или возбуждать дополнительные события. Например, элемент TextBox блокирует событие TextInput, а для клавиш-стрелок блокирует и событие KeyDown, но в то же время возбуждает свое событие TextChanged при изменении содержимого поля ввода.
Построим приложение, которое продемонстрирует обработку клавиатурных событий.
- Создайте решение EventsAndCommands вместе с новым WPF -проектом KeyEvents командой File/New/Project, для этого настройте окно мастера так
увеличить изображение
Обратите внимание на выбор версии библиотеки .NET Framework 3.0, при более низких версиях шаблоны для WPF станут недоступными. Стартовым новый проект тоже становится автоматически, поскольку он пока первый и единственный в решении. Дерево стартового проекта всегда выделяется в панели Solution Explorer полужирным шрифтом.
- Заполните файл разметки Window1.xaml следующим дескрипторным кодом
- Пройдитесь по разметке и командой Navigate to Event Handler контекстного меню для записей событий создайте заготовки обработчиков в файле процедурного кода
Некоторые события связаны с одними и теми же обработчиками, но лишних обработчиков мы таким образом все равно не создадим. Команда Navigate to Event Handler создает новый обработчик только тогда, когда он еще не существуют, а иначе приведет только к позиционированию на уже существующий.
- Запустите проект и убедитесь, что приведенная разметка реализует следующий интерфейс окна приложения
Без создания обработчиков для указанных в разметке событий мы бы не смогли откомпилировать приложение и получить приведенное окно. Если в разметке для какого-то события зарегистрирован обработчик, то перед запуском приложения его нужно обязательно создать, пусть даже с пустым телом. Поскольку компилятор будет настойчиво искать его определение в файле процедурного кода и выдаст ошибку в случае неуспеха. Другое дело, когда обработчик создан, но не присоединен к событию. В таком случае он считается одним из методов класса окна и компилятор протестовать не будет.
- Изучите код файла разметки, обеспечивающий требуемую компоновку элементов управления пользовательского интерфейса нашего упражнения
Следующим шагом мы должны заполнить каждый из обработчиков соответствующим кодом. Но вместо того, чтобы делать это по частям, приведем весь код сразу.
- Удалите из файла Window1.xaml.cs процедурного кода окна все что там есть и заполните его следующим содержимым, которое полностью согласуется с разметкой
В приведенном процедурном коде перехватываются события клавиатуры и в список выводится информация о нажатых клавишах, которая передается вместе с событием в обработчики через объекты их аргументов. Целевым объектом клавиатурных событий в данном коде является элемент текстового поля. Интерфейсные переключатели обеспечивают смену режимов обработки клавиатурных событий и иллюстрируют возможности библиотечных классов.
- Запустите и испытайте работу приложения, один из рабочих моментов которого может выглядеть так
- Изучите приведенный код процедурного файла, обратите внимание на некоторые приемы программирования
В обработчиках мы извлекаем информацию о событиях как RoutedEvent. Это значит, что события клавиатуры маршрутизируемые и их можно прослушивать и перехватывать не только в целевом объекте, но и в других местах логического дерева элементов. Убедимся в этом:
- В файле разметки переместите (вырежьте из... и вставьте в...) весь блок регистрации событий из элемента TextBox в самый внешний контейнер DockPanel, чтобы схематично окончательный код стал таким
- Запустите приложение и убедитесь, что функциональность его осталась прежней
Поставляемый событием в его обработчик объект e класса KeyEventArgs содержит не только информацию о нажатой клавише, но и сведения о состоянии модификаторов (расширителей), таких как Shift, Ctrl, Alt. Свойство e.KeyStates информирует о том, в каком состоянии находилась клавиша в момент генерации события: Down, None, Toggled.
Много полезной информации имеет свойство e.KeyboardDevice, представляющее экземпляр класса KeyboardDevice. Из его свойства e.KeyboardDevice.FocusedElement можно узнать, какой элемент в данный момент имеет фокус клавиатурного ввода. Из свойства e.KeyboardDevice.Modifiers объекта-аргумента обработчика можно определить состояние клавиатурных модификаторов (расширителей клавиатуры), например, так
private void KeyEvent(object sender, KeyEventArgs e) { if ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) Console.WriteLine("Нажато расширение Ctrl"); // Или аналогичный код if((e.KeyboardDevice.Modifiers & ModifierKeys.Alt) > 0) Console.WriteLine("Нажато расширение Alt"); // Или аналогичный код if ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) != 0) Console.WriteLine("Нажато расширение Shift"); }Объект e.KeyboardDevice имеет ряд полезных методов для прослушивания состояния любой интересующей нас клавиши
- public bool IsKeyDown(System.Windows.Input.Key key)
- public bool IsKeyUp(System.Windows.Input.Key key)
- public bool IsKeyToggled(System.Windows.Input.Key key)
Методы принимают клавишу, возбудившую событие, и сообщают, что с ней происходило в момент возникновения события. Вот пример
private void KeyEvent(object sender, KeyEventArgs e) { if (e.KeyboardDevice.IsKeyDown(e.Key)) Console.WriteLine("Клавиша {0} нажата", e.Key); if (e.KeyboardDevice.IsKeyUp(e.Key)) Console.WriteLine("Клавиша {0} отпущена", e.Key); // Попутно проверяем if(e.KeyboardDevice.IsKeyToggled(Key.NumLock)) Console.WriteLine("Клавиша NumLock включена"); }Не только в момент возникновения клавиатурного ввода мы можем получать информацию о состоянии клавиатуры в обработчике, но и в любой интересующий нас момент времени в любом месте программы. Для этого достаточно воспользоваться статическим классом System.Windows.Input. Keyboard, который отслеживает клавиатуру компьютера. По своим возможностям он значительно мощнее класса KeyboardDevice, который мы получаем в обработчике вместе с клавиатурным событием. Вот пример
// Где-то в программе bool Win, Ctrl, Alt, NumLock, CapsLock, ScrollLock; Win = (Keyboard.Modifiers & ModifierKeys.Windows) > 0; Ctrl = (Keyboard.Modifiers & ModifierKeys.Control) > 0; Alt = (Keyboard.Modifiers & ModifierKeys.Alt) > 0; NumLock = Keyboard.IsKeyToggled(Key.NumLock); CapsLock = Keyboard.IsKeyToggled(Key.Capital); ScrollLock = Keyboard.IsKeyToggled(Key.Scroll);Дата добавления: 2015-04-15; просмотров: 984;