Кнопки
63WPF --- Элементы управления WPF --- Кнопки
WPF распознает три типа кнопок: Button, CheckBox и RadioButton. Все эти кнопки являются наследниками класса ButtonBase.
Класс ButtonBase содержит лишь несколько членов. Он определяет событие Click и добавляет поддержку команд, которые позволяют подключать кнопки к высокоуровневым задачам приложений. Наконец, класс ButtonBase добавляет свойство ClickMode, которое определяет, когда кнопка генерирует событие Click в ответ на действия мыши. По умолчанию используется значение ClickMode.Release, которое означает, что событие Click будет сгенерировано после нажатия и последующего отпускания кнопки мыши. Однако можно сделать и так, чтобы событие Click возникало сразу при нажатии кнопки мыши (ClickMode.Press) или даже когда указатель мыши будет наведен на кнопку и задержится над ней (ClickMode.Hover).
Все кнопки поддерживают клавиши доступа, которые работают подобно мнемоническим командам в элементе управления Label. Для обозначения клавиши доступа служит символ подчеркивания. Когда пользователь нажмет клавишу <Alt> и клавишу доступа, возникнет событие Click данной кнопки.
Класс Button
Класс Button представляет вездесущую кнопку Windows. Он добавляет всего два доступных для записи свойства: IsCancel и IsDefault:
Если свойство IsCancel имеет значение true, то эта кнопка будет работать в окне как кнопка отмены. Если нажать клавишу <Esc>, когда фокус находится в текущем окне, то сработает эта кнопка.
Если свойство IsDefault имеет значение true, то эта кнопка считается кнопкой по умолчанию (она еще называется кнопкой принятия). Ее поведение зависит от текущей позиции в окне. Если указатель мыши находится на элементе управления, отличном от Button (например, TextBox, RadioButton, CheckBox и т.д.), то кнопка по умолчанию будет выделена голубоватым оттенком — почти так, как если бы она находилась в фокусе.
При нажатии клавиши <Enter> сработает эта кнопка. Однако если навести указатель мыши на другой элемент управления Button, то голубоватым оттенком будет выделена текущая кнопка, и при нажатии <Enter> будет приведена в действие именно эта кнопка, а не кнопка по умолчанию.
Многие пользователи используют такие клавиши быстрого доступа (особенно клавишу <Esc> для закрытия ненужного диалогового окна), поэтому есть смысл потратить время на определение этих деталей в каждом создаваемом вами окне. Но код обработки событий для кнопки по умолчанию и кнопки отмены придется написать вам, так как WPF не поддерживает это поведение.
В некоторых случаях имеет смысл сделать одну и ту же кнопку в окне и кнопкой отмены, и кнопкой по умолчанию. Примером может служить кнопка ОК в окне О программе. Однако в окне должна быть только одна кнопка отмены и одна кнопка по умолчанию. Если вы назначите несколько кнопок отмены, то нажатие клавиши <Esc> будет просто передавать фокус следующей кнопке по умолчанию, без ее активизации. А при наличии нескольких кнопок по умолчанию нажатие клавиши <Enter> приведет к непонятному поведению. Если в фокусе будет находиться элемент управления, отличный от Button, то при нажатии <Enter> фокус будет передан следующей кнопке по умолчанию. Если же в фокусе находится элемент управления Button, нажатие клавиши <Enter> активизирует его.
Класс Button содержит также загадочное свойство IsDefaulted, которое доступно только для чтения. Оно возвращает значение true для кнопки по умолчанию, если фокус принадлежит другому элементу управления, не принимающий клавишу <Enter>. В этой ситуации нажатие <Enter> приведет к активизации кнопки.
Например, элемент TextBox не принимает клавишу <Enter>, если свойство TextBox.AcceptsReturn не равно true. Если элемент управления TextBox со свойством TextBox.AcceptsReturn, равным true, находится в фокусе, то свойство IsDefaulted кнопки по умолчанию будет равно false. Если элемент TextBox со свойством AcceptsReturn, равным false, имеет фокус, то свойство IsDefaulted кнопки по умолчанию получает значение true.
Свойство IsDefaulted возвращает значение false, когда кнопка имеет фокус, даже если при этом нажатие клавиши <Enter> активизирует кнопку. Вряд ли вы будете использовать свойство IsDefaulted, хотя оно позволяет написать некоторые типы триггеров стилей. Если вам это не нужно, добавьте данное свойство в список малопонятных особенностей WPF, чтобы при случае озадачить своих коллег.
Классы ToggleButton и RepeatButton
Помимо Button, потомками класса ButtonBase являются еще три класса:
- GridViewColumnHeader
Заголовок столбца, реагирующий на щелчок мышью, если используется табличный элемент ListView.
- RepeatButton
В прижатом состоянии непрерывно генерирует события Click. Обычные кнопки генерируют событие Click только при полном щелчке на кнопке.
- ToggleButton
Кнопка с двумя состояниями (нажата и отпущена). Если щелкнуть на кнопке ToggleButton, она будет оставаться нажатой до тех пор, пока вы не щелкнете на ней снова. Иногда такое поведение называют залипающим щелчком (sticky click).
Классы RepeatButton и ToggleButton определены в пространстве имен System.Windows.Controls.Primitives, что означает, что сами по себе они применяются редко. Как правило, они используются для построения более сложных элементов управления или расширения возможностей путем наследования. Например, класс RepeatButton используется для создания высокоуровневого элемента управления ScrollBar (который, в свою очередь, входит в состав еще более высокоуровневого элемента ScrollViewer).
RepeatButton придает кнопкам со стрелками на концах полосы прокрутки их фирменное поведение: прокрутка продолжается, пока они нажаты. Точно так же ToggleButton применяется для порождения более полезных классов CheckBox и RadioButton, которые будут рассмотрены ниже.
В то же время ни RepatButton, ни ToggleButton не являются абстрактными классами, поэтому их можно непосредственно применять в пользовательских интерфейсах. ToggleButton очень удобно использовать внутри элемента ToolBar.
Класс CheckBox
Кнопки CheckBox и RadioButton — кнопки другого вида. Они являются потомками класса ToggleButton, а это означает, что пользователь может включать и выключать их (отсюда и слово toggle в названии — "переключение"). В случае CheckBox включение элемента управления означает установку в нем флажка.
Класс CheckBox не добавляет никаких членов, поэтому базовый интерфейс CheckBox определяется в классе ToggleButton. Более важно то, что ToggleButton добавляет свойство IsChecked. Свойство IsChecked является расширенным логическим, т.е. оно может принимать значения true, false или null. Понятно, что true представляет установленный флажок, a false — сброшенный. Значение null используется для представления неопределенного состояния, которое отображается в виде серого квадратика.
Неопределенное состояние обычно служит для представления не заданных значений или областей, в которых возможны противоречия. Например, если имеется флажок, который позволяет применять жирный шрифт в текстовом приложении, а выбранный фрагмент содержит как жирный, так и обычный текст, можно присвоить флажку значение null, чтобы обозначить неопределенное состояние.
Чтобы присвоить значение null в разметке WPF, нужно использовать расширение разметки Null:
<CheckBox IsChecked="{х:Null}">А check box in indeterminate state</CheckBox>
Наряду со свойством IsChecked класс ToggleButton добавляет свойство IsThreeState, которое определяет, может ли пользователь установить флажок в неопределенное состояние. Если свойство IsThreeState равно false (по умолчанию), то щелчки меняют состояние флажка между "установлен" и "сброшен", а неопределенное состояние можно задать только с помощью кода. Если свойство ThreeState равно true, то щелчки на флажке будут по очереди давать все три возможных состояния.
Класс ToggleButton определяет также три события, которые возникают, когда флажок принимает одно из конкретных состояний: Checked, Unchecked и Indeterminate. В большинстве случаев удобнее объединить эту логику в одном обработчике события Click, которое наследуется от класса ButtonBase. Событие Click возникает при каждом изменении состояния кнопки.
Класс RadioButton
Класс RadioButton также порожден от класса ToggleButton и использует то же свойство IsChecked и те же события Checked, Unchecked и Indeterminate. Кроме того, RadioButton добавляет еще одно свойство GroupName, которое позволяет управлять группировкой переключателей.
Обычно переключатели группируются их контейнером. Это означает, что если поместить три элемента RadioButton в панель StackPanel, то они формируют группу, из которой можно выбрать только один из них. А если поместить комбинацию переключателей в две разных панели StackPanel, получатся две независимые группы.
Свойство GroupName позволяет переопределить это поведение. С его помощью можно создать несколько групп в одном контейнере или одну группу, которая будет охватывать несколько контейнеров. В любом случае это выполняется просто: достаточно присвоить "одногруппным" переключателям имя одной и той же группы.