WPF, Кнопки

WPF розпізнає три типи кнопок: Button, CheckBox та RadioButton. Всі ці кнопки є спадкоємцями класуButtonBase.

Клас ButtonBase містить лише кілька членів. Він визначає подію Click та додає підтримку команд, які дозволяють підключати кнопки до високорівневих завдань додатків. Нарешті, клас ButtonBase додає властивість ClickMode, що визначає, коли кнопка генерує подію Click у відповідь дії миші. За замовчуванням використовується значення ClickMode.Release, яке означає, що подія Click буде згенерована після натискання та подальшого відпускання кнопки миші. Однак можна зробити так, щоб подія Click виникала відразу при натисканні кнопки миші (ClickMode.Press) або навіть коли покажчик миші буде наведений на кнопку і затримається над нею (ClickMode.Hover).

Всі кнопки підтримують клавіші доступу, які працюють подібно до мнемонічним командам в елементі управління Label. Для позначення клавіші доступу використовується символ підкреслення. Коли користувач натисне клавішу та клавішу доступу, виникне подія Click цієї кнопки.

Клас Button

Клас Button представляє всюдисущу кнопку Windows. Він додає всього два доступні для запису властивості:IsCancel іIsDefault :

Якщо властивість IsCancel має значення true, то ця кнопка працюватиме у вікні як кнопка скасування. Якщо натиснути клавішу , коли фокус знаходиться у поточному вікні, спрацює ця кнопка.

Якщо властивість IsDefault має значення true, то ця кнопка вважається стандартною кнопкою (вона ще називається кнопкою прийняття). Її поведінка залежить від поточної позиції у вікні. Якщо вказівник миші знаходиться на елементі керування, відмінному від Button (наприклад, TextBox, RadioButton, CheckBox і т.д.), то за замовчуванням кнопка будевиділена блакитним відтінком - майже так, якби вона знаходилася у фокусі.

При натисканні кнопки спрацює ця кнопка. Однак якщо навести покажчик миші на інший елемент керування Button, то блакитним відтінком буде виділено поточну кнопку, і при натисканні буде приведена в дію саме ця кнопка, а не кнопка за замовчуванням.

Багато користувачів використовують такі клавіші швидкого доступу (особливо клавішу для закриття непотрібного діалогового вікна), тому є сенс витратити час на визначення цих деталей у кожному вікні, що створюється. Але код обробки подій для кнопки за замовчуванням і кнопки скасування доведеться написати вам, оскільки WPF не підтримує цю поведінку.

У деяких випадках має сенс зробити ту саму кнопку у вікні і кнопкою скасування, і кнопкою за замовчуванням. Прикладом може бути кнопка ОК у вікні Про програму. Однак у вікні має бути лише одна кнопка скасування та одна кнопка за замовчуванням. Якщо ви призначите кілька кнопок скасування, то натискання клавіші просто передаватиме фокус наступній кнопці за замовчуванням, без її активізації. А за наявності кількох кнопок за замовчуванням натискання кнопки призведе до незрозумілої поведінки. Якщо у фокусі буде елемент управління, відмінний від Button, то при натисканні фокус буде переданий наступній кнопці за промовчанням. Якщо у фокусі знаходиться елемент керування Button, натискання клавіші активує його.

Клас Button містить також загадкову властивістьIsDefaulted, яка доступна тільки для читання. Воно повертає значення true для кнопки за замовчуванням, якщо фокус належить іншому елементу керування, який не приймає клавішу . У цій ситуації натискання призведе до активації кнопки.

Наприклад, елемент TextBox не приймає клавішу , якщо властивістьTextBox.AcceptsReturn не дорівнює true. Якщо елемент керування TextBox з властивістю TextBox.AcceptsReturn, рівним true, знаходиться у фокусі, то властивість IsDefaulted кнопки за умовчанням дорівнюватиме false. Якщо елемент TextBox з властивістю AcceptsReturn, що дорівнює false, має фокус, то властивість IsDefaulted кнопки за замовчуванням отримує значення true.

Властивість IsDefaulted повертає значення false, коли кнопка має фокус, навіть якщо натискання клавіші активує кнопку. Навряд чи ви будете використовувати властивості 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:

Поряд із властивістю 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 дозволяє перевизначити цю поведінку. З його допомогою можна створити кілька груп в одному контейнері або одну групу, яка охоплюватиме кілька контейнерів. У будь-якому випадку це виконуєтьсяпросто: досить присвоїти "одногрупним" перемикачам ім'я однієї й тієї групи.