Разработка пользовательского интерфейса на основе технологии Windows Presentation Foundation
Шрифт:
Ошибка. Отмеченный в конце предыдущего пункта недочет теперь приводит к неправильной работе программы. После нажатия на кнопку «=» символ «=» указывается между полями ввода; таким образом, информация о выбранной операции стирается, и при последующем нажатии кнопки «=» всегда выводится нулевой результат (для восстановления нормальной работы надо повторно выбрать требуемую операцию, нажав на связанную с ней кнопку). Обратите внимание на то, что в данном варианте программы при наступлении события Click для кнопки «=» выполняются два обработчика: button5_Click, который связан непосредственно с этой кнопкой, и button1_Click, связанный с ее родительским компонентом StackPanel. Поскольку событие Click является пузырьковым, вначале выполняется обработчик button5_Click.
Исправление. В начало метода button5_Click добавьте оператор
Комментарий
Добавленный
Итак, если для одного и того же туннелируемого или пузырькового события определен обработчик и в дочернем, и в родительском компоненте, то будут выполнены оба эти обработчика (причем порядок их вызова определяется категорией события). Однако имеется возможность прервать цепочку вызовов обработчиков данного события – для этого достаточно в одном из обработчиков пометить событие как обработанное описанным выше способом. Следует также заметить, что если туннелируемое событие (например, PreviewTextInput) помечено как обработанное, то не вызываются и все обработчики парного к нему пузырькового события (для события PreviewTextInput парным является TextInput). Соответствующий пример будет приведен в п. 3.4.
3.3. Простейшие приемы ускорения работы с помощью клавиатуры
Обратите внимание на добавленные символы подчеркивания в свойствах Content.
Результат. Кнопка «=» (button5) сделана кнопкой по умолчанию и отображается в окне особым образом (рис. 13); эквивалентом ее нажатия является нажатие на клавишу Enter. Символы, указанные на кнопках, подчеркиваются; это является признаком того, что с каждой кнопкой связана клавиша– ускоритель Alt+«подчеркнутый символ». Следует иметь в виду, что в последних версиях Windows символы, с которыми связываются клавиши-ускорители, подчеркиваются только в случае, если предварительно нажать клавишу Alt.
Рис. 13. Окно приложения CALC с подчеркнутыми символами в подписях кнопок
Комментарий
В WPF-проектах для выделения символов, с которыми требуется связать клавишу-ускоритель, необходимо указать перед ними символ подчеркивания «_» (в той редкой ситуации, когда символ подчеркивания требуется использовать в надписи на компоненте, надо ввести этот символ дважды). Заметим, что в проектах Windows Forms для связи символа с клавишей-ускорителем использовался символ «&». Он был заменен на символ «_», поскольку в xaml-файле (как и в любом XML-файле) символ «&» интерпретируется особым образом.
Ошибка. После нажатия на любую кнопку с арифметической операцией все последующие вычисления возвращают значение, равное 0 (поскольку первым символом метки label1 теперь является символ подчеркивания '_', не предусмотренный в операторе switch). Кроме того, символ операции, изображенный между полями ввода, тоже подчеркивается.
Исправление. Измените оператор в методе button1_Click следующим образом:
Комментарий
Для удаления одного или нескольких начальных символов строки достаточно вызвать метод TrimStart, указав удаляемые символы в качестве параметров (если параметры не указывать, то удаляются пробельные символы). Имеется также метод TrimEnd, удаляющий конечные символы, и метод Trim, удаляющий как начальные, так и конечные символы. Чтобы в нашем случае можно было использовать данный метод, необходимо выполнить явное преобразование свойства Content к типу string.
Недочет. Теперь, когда программа содержит средства для быстрого выполнения действий с помощью клавиатуры, более наглядно проявляется недочет, который имелся
Исправление. Добавьте в конструктор класса MainWindow оператор:
3.4. Использование обработчика событий от клавиатуры
Определите обработчик события PreviewTextInput для MainWindow:
Кроме того, измените метод button1_Click следующим образом:
Результат. Теперь для ввода любой операции достаточно нажать соответствующую клавишу (поскольку клавиша «–» может использоваться для ввода отрицательных чисел, в качестве ускорителя для кнопки «–» выбрана комбинация Shift+«–», соответствующая символу подчеркивания «_»). При вводе чисел игнорируются все клавиши, кроме цифровых, «–», «,» и Backspace (для обозначения символа, генерируемого клавишей Backspace, в C# можно использовать управляющую последовательность '\b'; нажатие этой клавиши обеспечивает удаление символа, расположенного слева от курсора в активном поле ввода).
Комментарии
1. При реализации описанных возможностей мы воспользовались тем, что событие PreviewTextInput является туннелируемым, т. е. вначале оно обрабатывается в родительском компоненте верхнего уровня (окне), а затем «спускается» по иерархии подчинения к тому компоненту, в котором возникло. Это позволило уже на уровне окна проанализировать введенный текст и выполнить требуемые действия по изменению арифметической операции (и, кроме того, «не пропустить» дальше те символы, которые не имеет смысла использовать в арифметических операндах). Напомним, что для прекращения последующих вызовов обработчиков данного события необходимо пометить событие как обработанное, положив свойство e.Handled равным true. Следует сказать, что пометка события как обработанного позволяет отменить вызов и стандартных обработчиков событий, связанных с компонентами (в нашем случае был отменен вызов стандартного обработчика события TextInput, обеспечивающего добавление набранного на клавиатуре символа в поле ввода).
2. Для имитации возникновения события, связанного с нажатием кнопок 1–4, в методе Window_PreviewTextInput вызывается обработчик данного события button1_Click. При этом необходимо указать нужную кнопку. Проще всего передать ее в качестве первого параметра обработчика, однако такой подход требует корректировки действий, содержащихся в методе button1_Click.
В операторе, добавленном в метод button1_Click, делается попытка привести параметр sender к типу Button. Если эта попытка успешна, то соответствующая кнопка помещается в переменную s. Если же указанное преобразование нельзя выполнить, то операция as возвращает значение null. Это означает, что обработчик был вызван родительским компонентом, а «истинный» адресат события содержится в свойстве e.Source, которое в этом случае приводится к типу Button и сохраняется в переменной s. Все описанные действия удалось реализовать в единственном операторе благодаря операции a ?? b, которая возвращает значение a, если оно не равно null, и b в противном случае.
Недочет 1. Если нажать клавишу пробела, находясь на одном из полей ввода, то пробел будет введен в это поле.
Это связано с тем, что пробел в WPF-приложениях обрабатывается особым образом: несмотря на то, что он является отображаемым символом и, казалось бы, нажатие на него должно приводить к возникновению события TextInput (и предшествующего ему события PreviewTextInput), этого не происходит. Таким образом, если мы хотим заблокировать ввод пробелов, это придется сделать с помощью дополнительного обработчика.