Введение в доступность приложений Windows — подготовка к UI Automation и требованиям разумного приспособления
· Го Комура · Доступность, UI Automation, Windows, WinForms, WPF, Разумное приспособление, Программы чтения с экрана, Закон о дискриминации, Бизнес-приложения
«Сотрудник, принятый в середине карьеры, с нарушением зрения не может пользоваться основной системой ввода заказов с программой чтения с экрана. Браузером и почтой пользуется без проблем, а вот чтение нашего бизнес-приложения работает неправильно. Можно ли что-то сделать?» — Такие консультации от ИТ-отделов заказчиков участились.
Один из контекстов — правовая рамка. Поправка 2021 года к Закону об устранении дискриминации в отношении лиц с инвалидностью вступила в силу 1 апреля 2024 года, и «предоставление разумного приспособления» лицам с инвалидностью стало обязанностью и для предприятий.1 Далее, отношение сотрудник–компания, как в открывающем примере (сфера занятости), — это область Закона о содействии трудоустройству лиц с инвалидностью, который обязал работодателей предоставлять разумное приспособление с апреля 2016 года.2 Идея, что «доступность — тема сайтов и к внутренним Windows-приложениям отношения не имеет», больше не держится ни юридически, ни на практике.
С другой стороны, с пола разработки «мы не знаем, что делать» — честное место. По доступности десктопных приложений Windows информации меньше, чем по Вебу, и волшебного решения задним числом нет. Пессимизм тоже не нужен. Если понять механизм, которым программа чтения с экрана читает приложение (UI Automation), и взять на вооружение основы имени, клавиатуры и цвета, удобство бизнес-приложения существенно растёт. И большая часть этого — улучшение, которое поднимает производительность каждого пользователя, с инвалидностью или без.
Рассчитанная на разработчиков японских бизнес-приложений и на ИТ-сотрудников, эта статья одним проходом связывает минимальную сортировку правовой рамки и стандартов, механизм UI Automation, реализацию в WinForms/WPF, работу с клавиатуры, цвет и контраст, инструменты проверки и реалистичный способ расставлять приоритеты.
flowchart TB
accTitle: Поток этой статьи
accDescr: Структура этой статьи, связывающая по порядку сортировку правовой рамки и стандартов, механизм UI Automation, реализацию в WinForms и WPF, работу с клавиатуры, цвет и контраст, инструменты проверки и то, как расставлять приоритеты
law["Сортировка правовой рамки и стандартов"] --> uia["Механизм UI Automation"]
uia --> impl["Реализация в WinForms/WPF"]
impl --> kb["Работа с клавиатуры"]
kb --> color["Цвет и контраст"]
color --> verify["Инструменты проверки"]
verify --> prio["Как расставлять приоритеты"]
Рис. 1: Статья связывает правовую рамку через механизм, реализацию, проверку и приоритеты в один поток.
1. Сначала вывод
- Предоставление разумного приспособления — обязанность и для предприятий с 1 апреля 2024 года. Когда лицо с инвалидностью выражает намерение снять барьер, требуется ответ в пределах, не составляющих чрезмерную нагрузку. Сфера занятости регулируется Законом о содействии трудоустройству лиц с инвалидностью, и это обязанность работодателя с апреля 2016 года.12
- Разумное приспособление — процесс «ответить на индивидуальный запрос через конструктивный диалог»; сделать приложение удобнее заранее — это «улучшение среды» (обязанность прилагать усилия). Совершенная предварительная поддержка не является обязанностью; важно не отказывать в диалоге в одностороннем порядке.1
- Технические критерии доступности сосредоточены в WCAG (JIS X 8341-3:2016). JIS X 8341-3:2016 — соответствующий стандарт с тем же содержанием, что WCAG 2.0, а WCAG2ICT W3C даёт указания, как применять его к не-веб-ПО. Десктопное приложение можно проверять тем же мышлением.34
- Программа чтения с экрана читает приложение через UI Automation (UIA). Свойства, которые держит каждый элемент дерева UIA, — Name, ControlType и подобные — и шаблоны управления вроде Invoke, Value и SelectionItem — материал для объявления и операции.5
- Кнопка с пустым Name объявляется только как «кнопка». Исправление высшего приоритета — именование. WinForms использует AccessibleName и привязку Label к порядку табуляции; WPF — AutomationProperties.Name/LabeledBy.67
- Возможность добраться до каждой функции одной клавиатурой — критерий успеха WCAG (2.1.1) и одновременно сама скорость ввода опытного оператора. Постановка порядка табуляции, клавиш доступа и индикации фокуса напрямую связана с эффективностью для каждого пользователя.8
- Берите коэффициент контраста текста 4,5:1 и выше как ориентир и не передавайте информацию одним только цветом. В теме контраста (высокая контрастность) уважайте системные цвета, а не жёстко зашитые.89
- Сочетайте проверку FastPass в Accessibility Insights for Windows и практическую проверку программой чтения с экрана. Поскольку они сидят на одном фундаменте UIA, эта работа взаимно окупается и с активами автоматического UI-тестирования вроде FlaUI.10
- Не нужно чинить все экраны сразу. Реалистичный порядок: (1) с экранов, которыми пользуется этот пользователь, (2) новая разработка соответствует стандарту, (3) раскатывайте вширь, чиня общие элементы.
Одним предложением: поддержка доступности — это «выставить правильное имя и операции на дереве UIA и держать основы клавиатуры и цвета».
2. Сортировка правовой рамки и стандартов — что изменилось, когда «стало обязанностью»
2.1. Закон об устранении дискриминации в отношении лиц с инвалидностью — с апреля 2024 года предприятия тоже обязаны предоставлять разумное приспособление
Закон об устранении дискриминации в отношении лиц с инвалидностью запрещает «несправедливое дискриминационное обращение» с лицами с инвалидностью со стороны административных органов и предприятий и требует «предоставления разумного приспособления». В поправке 2021 года (Рэйва 3) предоставление разумного приспособления предприятиями, которое было обязанностью прилагать усилия, стало обязанностью, и изменённый закон вступил в силу 1 апреля 2024 года (Рэйва 6).1
Согласно листовке Кабинета министров, предоставление разумного приспособления — это ответить в пределах, не составляющих чрезмерную нагрузку, когда лицо с инвалидностью выражает намерение, что нужен какой-то ответ, чтобы снять барьер в обществе. И поскольку содержание различается по характеристике инвалидности, сцене и ситуации, подчёркивается «конструктивный диалог», в котором лицо с инвалидностью и предприятие наслаивают диалог и вместе рассматривают ответ. Односторонний отказ от конструктивного диалога указан как потенциально составляющий нарушение обязанности предоставлять разумное приспособление.1
Здесь важны два практических различения.
- «Иметь всё готовым заранее» — не то, что стало обязанностью. Предварительные меры улучшения, направленные на неопределённое число лиц с инвалидностью — мягкая сторона вроде пересмотра руководства и обучения, жёсткая сторона вроде безбарьерности помещения — называются «улучшением среды», и это обязанность прилагать усилия.1 Привести бизнес-приложение заранее в состояние, пригодное для программы чтения с экрана, можно мыслить как усилие по улучшению среды. Чем дальше зашло улучшение среды, тем легче нагрузка индивидуального разумного приспособления.
- Сфера занятости регулируется не Законом об устранении дискриминации в отношении лиц с инвалидностью, а Законом о содействии трудоустройству лиц с инвалидностью. Та же листовка также указывает, что занятость и работа следуют положениям Закона о содействии трудоустройству лиц с инвалидностью.1 И по этому закону, поправкой, вступившей в силу в апреле 2016 года (Хэйсэй 28), запрет дискриминации по инвалидности в занятости и предоставление разумного приспособления в пределах, не составляющих чрезмерную нагрузку, вменены работодателям.2 Открывающая консультация «сотрудник не может пользоваться бизнес-приложением» на деле уже давно в зоне обязанности, задолго до 2024 года.
flowchart TB
accTitle: Позиционирование разумного приспособления и улучшения среды
accDescr: Отношение между обычным предприятием и лицом с инвалидностью регулируется законом о дискриминации, и предоставление разумного приспособления ответом на индивидуальный запрос через конструктивный диалог — обязанность с апреля 2024 года; сфера занятости — обязанность работодателя с апреля 2016 года по закону о занятости; сделать приложение удобнее заранее — улучшение среды, обязанность прилагать усилия
scene{"Какая сцена?"}
scene -->|Предприятие + инвалидность| kaisho["Закон о дискриминации"]
scene -->|Занятость / работа| koyou["Закон о занятости"]
kaisho --> moushide["Запрос через диалог"]
moushide --> hairyo["Предоставить приспособление"]
hairyo -.-> hairyoN["Обязанность с 2024"]
koyou --> koyougimu["Предоставить приспособление"]
koyougimu -.-> koyouN["Обязанность с 2016"]
kaisho -.-> kankyo["Приложение удобнее заранее"]
kankyo -.-> kankyoN["Улучшение среды"]
kankyoN -.-> kankyoN2["обязанность усилий"]
kankyo -.-> moushide
Рис. 2: Применимый закон расходится по сцене; разумное приспособление — обязанность, а предварительные правки — улучшение среды, обязанность прилагать усилия.
Как индивидуальный случай трактуется в праве, зависит от ситуации. Эта статья не заходит в юридическое толкование; она идёт с точки зрения того, что может сделать инженер, когда просят ответ. По первичным источникам обращайтесь к материалам Кабинета министров и Министерства здравоохранения, труда и социального обеспечения.12
2.2. JIS X 8341-3 и WCAG — «веб-критерии» распространяются и на ПО
На стороне технических критериев они сосредоточены в JIS X 8341-3:2016. Этот стандарт — соответствующий стандарт ISO/IEC 40500:2012, и тело стандарта имеет то же содержание, что WCAG 2.0 W3C.3 Если хотите конкретно знать, из чего состоит «поддержка доступности», читать критерии успеха WCAG (теперь расширенные в WCAG 2.1/2.2) — кратчайший путь, и опубликован японский перевод WAIC.8
Вопрос «WCAG — критерий для веб-контента?» справедлив, но W3C в Group Note под названием WCAG2ICT (Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies) разобрал, как применять критерии успеха WCAG 2.0/2.1/2.2 к не-веб-документам и ПО.4 Иначе говоря, мышление вроде «текстовые альтернативы», «контраст», «работа с клавиатуры» и «цвет — не единственное средство» можно применить к десктопному приложению Windows в той же рамке, что и к Вебу. Главы с 3-й этой статьи опускают это мышление в конкретную реализацию WinForms/WPF.
flowchart TB
accTitle: Связь JIS X 8341-3 и WCAG
accDescr: JIS X 8341-3:2016 — соответствующий стандарт с тем же содержанием, что WCAG 2.0, а WCAG2ICT показывает, как применять критерии успеха WCAG к не-веб-ПО, поэтому десктопное приложение Windows можно проверять в той же рамке
wcag["WCAG 2.0 (W3C)"] ---|Соответствующий стандарт с тем же содержанием| jis["JIS X 8341-3:2016"]
wcag --> ict["WCAG2ICT"]
ict --> soft["Применить к не-веб-ПО"]
soft --> app["Десктопное приложение Windows"]
Рис. 3: JIS X 8341-3:2016 — соответствующий стандарт WCAG 2.0, а WCAG2ICT распространяет те же критерии на десктопные приложения.
3. Как вспомогательные технологии читают приложение — тройка UI Automation
3.1. Дерево UIA, свойства и шаблоны управления
В Windows встроена основа доступности под названием UI Automation (UIA). UIA — механизм, который позволяет вспомогательным технологиям вроде программы чтения с экрана получать информацию об интерфейсе и управлять им средствами, отличными от стандартного ввода, и посредничает между стороной приложения (провайдер) и стороной вспомогательной технологии (клиент).5
Мир UIA можно понять как следующую тройку.5
| Элемент | Роль | Типичные примеры |
|---|---|---|
| Дерево UIA | Дерево, которое начинается с рабочего стола как корня и продолжается окно → элемент. Вспомогательная технология ходит по этому дереву, чтобы схватить интерфейс | Окно, панель, кнопка, поле правки |
| Свойства | Значения, которые представляют природу каждого элемента | Name (назначение), ControlType (вид), AutomationId (идентификатор), IsEnabled, IsKeyboardFocusable |
| Шаблоны управления | Словарь «операций, которые можно сделать» по виду | Invoke (нажать), Value (читать/писать значение), SelectionItem (выбрать), Toggle (вкл/выкл), ExpandCollapse (развернуть/свернуть) |
Когда программа чтения с экрана фокусирует кнопку, объявление «кнопка Подтвердить заказ» — грубо говоря, сочетание Name + тип элемента. Когда пользователь выполняет операцию «выполнить», вспомогательная технология нажимает эту кнопку через шаблон Invoke. Иначе говоря, если Name и шаблоны выставлены правильно, можно читать и управлять; если не выставлены, это всё равно что не существует, даже если видно на экране.
flowchart TB
accTitle: Тройка UI Automation
accDescr: Приложение как провайдер выставляет свойства и шаблоны управления каждого элемента на дереве UIA; программа чтения с экрана как клиент объявляет Name и ControlType и действует через шаблоны вроде Invoke
app["Приложение (провайдер)"] --> tree["Дерево UIA"]
tree --> prop["Свойства (Name, ControlType и подобные)"]
tree --> pat["Шаблоны (Invoke, Value и подобные)"]
sr["Программа чтения (клиент)"] -->|Объявляет| prop
sr -->|Управляет| pat
Рис. 4: Программа чтения с экрана использует свойства и шаблоны, которые приложение выставило на дереве UIA, для объявления и операции.
3.2. Программа чтения с экрана — клиент UIA
Основные программы чтения с экрана на Windows включают Narrator, встроенный в Windows; NVDA,11 свободный и с открытым исходным кодом; и PC-Talker, коммерческий продукт, широко используемый в Японии. Стиль объявления различается, но основной путь чтения интерфейса десктопного приложения во всех случаях — UIA. Поэтому ответ стороны приложения — не «поддержка конкретной программы чтения», а сосредоточен на выставлении правильной информации в UIA.
flowchart TB
accTitle: Общий путь основных программ чтения с экрана
accDescr: Если приложение выставляет правильную информацию в UIA, Narrator, NVDA и PC-Talker все могут читать интерфейс тем же путём, поэтому ответ стороны приложения не нацелен на конкретную программу чтения, а сосредоточен на выставлении в UIA
app["Приложение"] -->|Выставляет информацию| uia["UI Automation (UIA)"]
uia --> nar["Narrator"]
uia --> nvda["NVDA"]
uia --> pct["PC-Talker"]
app -.-> goal["Ответ сосредоточен на выставлении в UIA"]
Рис. 5: Основные программы чтения с экрана все берут UIA как путь, поэтому ответ приложения сосредоточен на выставлении в UIA.
3.3. Как объявляется «кнопка с пустым Name»?
Конкретный пример. Предположим, на панели инструментов есть кнопка Сохранить, которая показывает только иконку дискеты. Зрячему пользователю иконка передаёт смысл, но если Name оставлен пустым, программа чтения объявляет эту кнопку только как «кнопка». Если соседние «Открыть» и «Печать» такие же, пользователь слышит только «кнопка, кнопка, кнопка» и не имеет средства узнать, какая есть какая. Руководство Microsoft по исправлению доступности также перечисляет кнопку без Name и изображение, объявляемое только как «Image», как типичные проблемы, которые останавливают работу пользователя.7
К счастью, и стандартные элементы WinForms, и WPF имеют поддержку UIA с самого начала, и во многих случаях Name решается автоматически из текста или метки. Ломается обычно одно из (1) только иконка, нет материала для имени, (2) нет связи с меткой, или (3) пользовательская отрисовка, которая не кладёт информацию на дерево UIA. Следующие две главы смотрят, как это чинить по фреймворку.
flowchart TB
accTitle: Три типичных способа, которыми ломается объявление
accDescr: Объявление ломается, когда нет материала для имени, потому что это только иконка, когда нет связи с меткой, или когда пользовательская отрисовка не кладёт информацию на дерево UIA, и в итоге объявляется только как кнопка
c1["Только иконка, нет материала"] --> broken["Name становится пустым"]
c2["Нет связи с меткой"] --> broken
c3["Пользовательская отрисовка не выдаёт информацию"] --> broken
broken --> result["Объявляется только как кнопка"]
Рис. 6: Поломка объявления обычно сводится к одному из трёх шаблонов: недостаток материала для имени, недостаток связи или пользовательская отрисовка.
4. Реализация в WinForms — AccessibleName и порядок табуляции
4.1. Элементы, у которых Text становится Name автоматически, и элементы, у которых нет
В WinForms элемент, который показывает текст, например Button или CheckBox, использует значение свойства Text как UIA Name. С другой стороны, ComboBox, ListBox, ListView, PictureBox, ProgressBar, TabControl, TextBox, TreeView и подобные не делают Text именем. Им нужно имя другим способом.6
Самый поддерживаемый способ — поставить описательную Label в непосредственно предшествующем порядке табуляции целевого элемента. Если задать TabIndex целевого элемента сразу после TabIndex Label, текст этой Label автоматически используется как UIA Name. Метка, видимая на экране, и объявление совпадают, и формулировку не нужно вести дважды.612
Если Label поставить нельзя, задайте AccessibleName явно. Можно также задать AccessibleDescription, если нужно дополнительное пояснение, и AccessibleRole, если роль отличается от внешнего вида.13
flowchart TB
accTitle: Как решается имя элемента WinForms
accDescr: Для Button и подобных Text становится UIA Name как есть; для элементов вроде TextBox, чей Text не переиспользуется, берётся текст Label в непосредственно предшествующем порядке табуляции; если Label поставить нельзя, задайте AccessibleName явно
ctrl["Элемент"] --> qtext{"Вид, у которого Text становится Name?"}
qtext -->|Да| usetext["Text становится Name как есть"]
qtext -->|Нет| qlabel{"Label в непосредственно предшествующем порядке табуляции?"}
qlabel -->|Да| uselabel["Текст Label используется как Name"]
qlabel -->|Нет| explicit["Задайте AccessibleName явно"]
Рис. 7: Для Name в WinForms выбирайте, как его решать, в порядке Text, Label в непосредственно предшествующем порядке табуляции, AccessibleName.
// Кнопка панели только с иконкой: явно укажите имя для объявления
saveToolStripButton.AccessibleName = "Save";
// Кнопка только с изображением: имя + дополнительное пояснение
btnSearchCustomer.AccessibleName = "Search customer";
btnSearchCustomer.AccessibleDescription = "Search the customer master by customer code or name";
// Задайте напрямую на поле ввода, где нельзя поставить Label в непосредственно предшествующем порядке табуляции
txtOrderNo.AccessibleName = "Order number";
// PictureBox, переиспользованный как отображение диаграммы: согласуйте и роль с реальностью
pictureBoxChart.AccessibleRole = AccessibleRole.Chart;
pictureBoxChart.AccessibleName = "Monthly order-count chart";
Как оговорка: если один раз задать AccessibleName на панели свойств Visual Studio, а затем очистить, в файле дизайнера может остаться пустая строка и мешать разрешению имени по умолчанию. Удалите соответствующую строку из файла дизайнера.6
flowchart TB
accTitle: Проблема оставшегося пустого AccessibleName
accDescr: Если один раз задать AccessibleName на панели свойств, а затем очистить, пустая строка остаётся в файле дизайнера и мешает разрешению имени по умолчанию, поэтому это чинят удалением соответствующей строки из файла дизайнера
set["Задать AccessibleName"] --> erase["Очистить на панели свойств"]
erase --> remain["Остаётся пустая строка"]
remain --> block["Мешает разрешению имени по умолчанию"]
block -.-> fix["Удалить соответствующую строку из файла дизайнера"]
Рис. 8: Очистка на панели свойств всё равно оставляет пустую строку, поэтому чинят удалением соответствующей строки из файла дизайнера.
4.2. Типичные улучшения на экране ввода заказов
Места, которые мы на деле часто чиним в бизнес-приложениях, сведены в чек-лист.
| Типичное состояние | Проблема | Как чинить |
|---|---|---|
| ToolStripButton только с иконкой | Объявляется только как «кнопка» | Задайте AccessibleName |
| Рядом с TextBox есть Label, но порядок табуляции разбросан | Имя поля ввода пустое или становится чужим | Поставьте поле ввода сразу после TabIndex Label |
| PictureBox используется как кнопка через Click | Роль не передаётся как кнопка, и с клавиатуры нажать нельзя | Замените на Button или задайте AccessibleRole/AccessibleName плюс поддержку клавиатуры |
| Заголовок столбца DataGridView пустой или только символы | Смысл столбца неясен, когда объявляется ячейка | Задайте осмысленное имя столбца в HeaderText |
| Для группировки содержимого используется только Panel, а заголовок — изображение | Непонятно, какая это группа ввода | Используйте GroupBox или сделайте заголовок Label |
Каждое — правка в несколько строк, но для пользователя программы чтения это развилка между «экран, которым нельзя пользоваться» и «экран, которым можно пользоваться».
5. Реализация в WPF — AutomationProperties и AutomationPeer
5.1. AutomationProperties.Name / LabeledBy / HelpText
В WPF элемент, чей Content — строка, например Button, использует это содержимое как UIA Name. Кнопка только с иконкой (Image или Path) не имеет материала для Name, поэтому его указывают через AutomationProperties.Name, а если рядом есть отображаемый текст — связывают через AutomationProperties.LabeledBy.7
У TextBox есть важная оговорка. Text у TextBlock переиспользуется как Name, но Text у TextBox выставляется на стороне свойства UIA Value и не становится Name. Для поля ввода связать отображаемую метку-TextBlock через LabeledBy — первый кандидат. Объявление и отображение на экране совпадают, и формулировку тоже не нужно вести дважды.14
<!-- Поле ввода: свяжите отображаемую метку через LabeledBy -->
<TextBlock x:Name="OrderNoLabel" Text="Order number" />
<TextBox
AutomationProperties.LabeledBy="{Binding ElementName=OrderNoLabel}"
AutomationProperties.AutomationId="OrderNoTextBox" />
<!-- Кнопка только с иконкой: укажите имя и при необходимости дополнение -->
<Button
AutomationProperties.Name="Confirm order"
AutomationProperties.HelpText="Confirm the order being entered and allocate inventory">
<Path Data="{StaticResource CheckIconGeometry}" Width="16" Height="16" />
</Button>
flowchart TB
accTitle: Как решается имя элемента WPF
accDescr: Элемент, чей Content — строка, использует это содержимое как Name; иначе связать ближайшую отображаемую метку через LabeledBy — первый кандидат; если и её нет, задайте AutomationProperties.Name; Text у TextBox выставляется на стороне Value, не как Name
ctrl["Элемент"] --> qc{"Content — строка?"}
qc -->|Да| auto["Содержимое становится Name"]
qc -->|Нет| ql{"Ближайшая отображаемая метка?"}
ql -->|Да| lb["Связать через LabeledBy"]
ql -->|Нет| nm["Задать Name явно"]
tbx["Text у TextBox"] -.-> val["Выставляется как Value, не Name"]
Рис. 9: Для Name в WPF решайте в порядке строка Content, LabeledBy, явная установка; Text у TextBox не становится Name.
Дополнительную информацию, которая не помещается в Name, можно выставить через AutomationProperties.HelpText.7 Кроме того, AutomationId — идентификатор для идентификации элементов в автоматическом UI-тестировании, поэтому соглашение об именовании на этапе проектирования экрана окупается позже (подробно в «Автоматическое UI-тестирование десктопных приложений Windows»).
5.2. Пользовательскому элементу нужен AutomationPeer
Пользовательский элемент, который вы рисуете сами, как есть не может выставить осмысленную информацию на дерево UIA. В WPF переопределяют OnCreateAutomationPeer на классе, производном от UIElement, и возвращают класс, производный от AutomationPeer, чтобы выставить имя, вид и шаблоны. Если наследуете существующий элемент, наследование соответствующего Peer (ButtonBaseAutomationPeer для ButtonBase) позволяет перенять уже реализованное поведение.15
flowchart TB
accTitle: Как информация выставляется через AutomationPeer
accDescr: Пользовательский элемент выставляет имя, вид и шаблоны, переопределяя OnCreateAutomationPeer и возвращая класс, производный от AutomationPeer; если наследуете существующий элемент, наследуйте соответствующий Peer и перенимайте уже реализованное поведение
custom["Пользовательский элемент"] --> ov["OnCreateAutomationPeer"]
ov --> peer["Вернуть класс, производный от Peer"]
peer --> pub["Выставить имя, вид и шаблоны"]
inherit["Наследовать существующий элемент"] -.-> basepeer["Наследовать соответствующий Peer"]
basepeer -.-> reuse["Перенять уже реализованное поведение"]
Рис. 10: Пользовательский элемент возвращает Peer из OnCreateAutomationPeer и выставляет информацию в UIA.
// Пример элемента, который пользовательски рисует статус линии как цветную лампу
public class StatusLamp : Control
{
public static readonly DependencyProperty IsOnlineProperty =
DependencyProperty.Register(nameof(IsOnline), typeof(bool), typeof(StatusLamp),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender, OnIsOnlineChanged));
public bool IsOnline
{
get => (bool)GetValue(IsOnlineProperty);
set => SetValue(IsOnlineProperty, value);
}
internal static string NameFor(bool isOnline)
=> isOnline ? "Line status: online" : "Line status: offline";
private static void OnIsOnlineChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Поднимите событие изменения свойства UIA в момент смены значения. Без этого
// программа чтения держит старое имя и не может заметить смену состояния
if (UIElementAutomationPeer.FromElement((UIElement)d) is AutomationPeer peer)
{
peer.RaisePropertyChangedEvent(
AutomationElementIdentifiers.NameProperty,
NameFor((bool)e.OldValue), NameFor((bool)e.NewValue));
}
}
protected override AutomationPeer OnCreateAutomationPeer()
=> new StatusLampAutomationPeer(this);
}
public class StatusLampAutomationPeer : FrameworkElementAutomationPeer
{
public StatusLampAutomationPeer(StatusLamp owner) : base(owner) { }
protected override AutomationControlType GetAutomationControlTypeCore()
=> AutomationControlType.Text; // Эквивалент текста, если это отображение статуса без операции
protected override string GetNameCore()
=> StatusLamp.NameFor(((StatusLamp)Owner).IsOnline);
}
Вернуть имя недостаточно; сообщить событием в момент смены — тоже работа Peer. У вспомогательной технологии нет собственного момента повторно забрать значение, поэтому реализация без события изменения находится в состоянии «правильно только когда спросят снова», и пользователь программы чтения не узнаёт о смене состояния.
sequenceDiagram
accTitle: Поток сообщения программе чтения о смене состояния
accDescr: В момент смены значения элемента AutomationPeer поднимает событие изменения свойства Name; вспомогательная технология сама повторно не забирает, поэтому без события остаётся на старом имени и не может заметить смену
participant c as Элемент
participant p as AutomationPeer
participant s as Программа чтения
c->>p: Значение IsOnline меняется
p->>s: Поднять событие изменения свойства Name
s->>s: Объявить новое состояние
Note over s: Без события остаётся на старом имени
Рис. 11: Смена значения доходит до программы чтения только когда AutomationPeer сообщает её событием изменения.
Если у пользовательского элемента есть операция (можно нажать, изменить значение, выбрать), переопределите GetPattern и предоставьте интерфейс шаблона вроде IInvokeProvider или IRangeValueProvider.15 Суть в том, что если Peer тоже собрать на стороне общей библиотеки элементов, каждый экран, который её использует, автоматически становится поддержанным. Это фундамент «раскатки вширь» главы 9.
6. Можно ли добраться до каждой функции одной клавиатурой?
Критерий успеха WCAG 2.1.1 (Keyboard) требует, чтобы вся функциональность содержимого была управляема через клавиатурный интерфейс.8 Пользователь программы чтения с экрана в принципе не использует мышь, поэтому функция, до которой нельзя добраться с клавиатуры, — то же самое, что функция, которой нет. Точки осмотра такие.
| Точка зрения | Что подтвердить | Основные средства в WinForms / WPF |
|---|---|---|
| Порядок табуляции | Совпадает ли порядок движения клавиши Tab с визуальным порядком (слева сверху → справа снизу)? | Приведение TabIndex в порядок, задание TabStop |
| Клавиша доступа | Можно ли перейти напрямую к главному пункту через Alt+букву? | В WinForms — & в Text; в WPF — _ в заголовке |
| Сочетание клавиш | Есть ли отдельная клавиша для частых операций (сохранить, найти, подтвердить)? | Назначение Ctrl+S и подобных, показ в меню |
| Индикация фокуса | Можно ли глазами проследить, где сейчас фокус? | Не убирайте прямоугольник фокуса; рисуйте сами при пользовательской отрисовке |
| Функции только мышью | Есть ли функция, доступная только двойным щелчком, правым щелчком, перетаскиванием или наведением? | Предложите ту же функцию также из меню или клавишей |
| Диалог | Работают ли Enter = кнопка по умолчанию и Esc = отмена? | AcceptButton/CancelButton, IsDefault/IsCancel |
Практическое руководство по доступности WinForms также перечисляет как основы постановку метки в непосредственно предшествующем порядке табуляции поля ввода и клавиши доступа на элементах и меню, к которым пользователь хочет перейти.12
Что хочется подчеркнуть: это не «лишняя стоимость поддержки инвалидности». В рутинной работе вроде ввода заказов возможность завершить ввод, не снимая рук с домашней позиции, как есть решает пропускную способность оператора. Беспорядочный порядок табуляции или операция, требующая мыши, — дефект, который каждый день чуть срезает производительность каждого пользователя. Поддержка доступности и эффективность клавиатуры — просто два имени одной работы (о приоритетах по среде использования см. также «UX-проектирование Windows-приложений»).
flowchart TB
accTitle: Двойной эффект наведения порядка в клавиатуре
accDescr: Постановка порядка табуляции, клавиш доступа и индикации фокуса даёт сразу два эффекта — пользователь вспомогательных технологий может добраться до функции, и скорость ввода каждого оператора — а функция, доступная только мышью, равна несуществующей
seibi["Навести порядок в клавиатуре"] --> a11y["Пользователи вспом. технологий"]
seibi --> speed["Скорость каждого оператора"]
mouse["Функция только мышью"] -.-> none["Как несуществующая"]
Рис. 12: Наведение порядка в работе с клавиатуры одновременно реализует поддержку вспомогательных технологий и эффективность для каждого пользователя; функция только мышью равна несуществующей.
7. Цвет и контраст — 4,5:1 и «цвет — не единственное средство»
7.1. Ориентир коэффициента контраста — 4,5:1
Критерий успеха WCAG 1.4.3 (Contrast (Minimum)) требует коэффициента контраста не менее 4,5:1 для текста и изображений текста и не менее 3:1 для крупного текста.8 Современный дизайн, который кладёт светло-серый текст на белый фон, нередко не дотягивает до этого критерия. Среди пользователей бизнес-приложения есть люди, у которых зрение и цветовое зрение изменились с возрастом, и люди, которые пользуются им в плохо освещённой среде вроде завода. Возьмите привычку измерять контраст-чекером на ревью дизайна.
7.2. Не передавайте информацию одним только цветом
Критерий успеха 1.4.1 (Use of Color) состоит в том, что цвет не должен быть единственным визуальным средством передачи информации.8 Типичные примеры в бизнес-приложении такие.
- Показывать строку ошибки только красным текстом → также дайте иконку ошибки и столбец сообщения
- Показывать обязательное поле только цветом метки → добавьте «*» или формулировку «Обязательно»
- Показывать статус только цветом лампы → сделайте цвет + форму или формулировку («Работает», «Остановлено»)
Учитывая разнообразие цветового зрения, это тоже не «особый ответ», а основа проектирования отображения.
flowchart TB
accTitle: Замена информации, передаваемой одним только цветом
accDescr: Отображение, которое показывает ошибку только красным текстом, заменяется иконкой ошибки плюс столбцом сообщения; отображение обязательного поля только цветом метки заменяется добавлением формулировки Обязательно; отображение статуса только цветом лампы заменяется сочетанием формы или формулировки
err["Ошибка только красным текстом"] --> erra["Также дать иконку и формулировку"]
req["Обязательное только цветом метки"] --> reqa["Добавить формулировку Обязательно"]
lamp["Статус только цветом лампы"] --> lampa["Сочетать цвет с формой или формулировкой"]
Рис. 13: Типичные примеры передачи одним только цветом заменяются сочетанием иконки, формулировки и формы или текста.
7.3. Следование теме контраста (высокая контрастность)
В Windows есть темы контраста (раньше — высокая контрастность), которые переключают на цветовую схему с сильным разделением переднего плана и фона; пользователь может выбирать и править встроенные темы, спроектированные так, чтобы коэффициент контраста был в целом 7:1 и выше.9 Принцип стороны приложения прост: не зашивайте цвета жёстко; уважайте системные цвета.
- WinForms: если оставить ForeColor/BackColor по умолчанию, используются цветовые настройки пользователя. Там, где вы применили свой цвет, определяйте через SystemInformation.HighContrast, переключайтесь на схему на базе SystemColors и отслеживайте смену настроек событием UserPreferenceChanged.12
- WPF/WinUI: если ссылаетесь на ресурсы класса SystemColors, вы следуете смене темы. Места, которые вы залили своей кистью, становятся причиной поломки.9
flowchart TB
accTitle: Следование теме контраста
accDescr: Места, где цвет зашит жёстко, ломаются при переключении на тему контраста, поэтому переключайтесь на схему на базе SystemColors и отслеживайте событием смены настроек; если ссылаетесь на системные цвета, можете автоматически следовать цветам пользователя
theme["Переключение на тему контраста"] --> qh{"Как задан цвет?"}
qh -->|Зашит жёстко| broken["Цветовая схема ломается"]
qh -->|Ссылка на системный цвет| ok["Автоматически следует цветам пользователя"]
broken -.-> fix["Переключиться на SystemColors"]
fix -.-> ev["Отслеживать событием смены настроек"]
Рис. 14: Под темой контраста ломаются только места, где цвет зашит жёстко; ссылка на системный цвет следует автоматически.
Кроме того, пользователь со слабым зрением часто использует высокое увеличение ОС (масштабирование DPI), поэтому поддержка высокого DPI — тоже часть поддержки доступности. Приложение, чей макет ломается при 125%–200%, в этой точке уже непригодно. Подробности — в «Поддержка высокого DPI в WinForms» и «Высокий DPI в WPF».
8. Проверка на практике — Accessibility Insights и практическая проверка программой чтения
8.1. Accessibility Insights for Windows
Microsoft предоставляет Accessibility Insights for Windows как инструмент проверки доступности приложений Windows с тремя основными применениями.10
- Live Inspect: достаточно навести мышь на элемент или сфокусировать его с клавиатуры — и можно подтвердить его свойства UIA (Name, ControlType, шаблоны и подобные). Кратчайшее средство увидеть «какой Name у этой кнопки».
- FastPass: лёгкая проверка, которая за менее чем пять минут обнаруживает проблемы доступности с высоким влиянием. Проблемы, которые можно судить механически, например отсутствующий Name, можно инвентаризировать по каждому новому экрану.
- Troubleshooting: помогает диагностировать и чинить конкретную проблему. От обнаруженной проблемы можно пройти напрямую к руководствам по исправлению по фреймворкам, которые цитирует и эта статья.
Inspect.exe и AccEvent, входящие в Windows SDK, тоже могут подтвердить дерево UIA и свойства, но позиционируются как устаревшие инструменты, и теперь рекомендуется переход на Accessibility Insights.10
flowchart TB
accTitle: Три применения Accessibility Insights
accDescr: Accessibility Insights for Windows даёт подтверждение свойств UIA через Live Inspect, лёгкую проверку проблем с высоким влиянием через FastPass и помощь в диагностике и исправлении проблемы через Troubleshooting; рекомендуется переход с устаревших инструментов вроде Inspect.exe
ai["Accessibility Insights"] --> live["Live Inspect"]
ai --> fast["FastPass"]
ai --> ts["Troubleshooting"]
live --> livef["Подтвердить свойства UIA"]
fast --> fastf["Обнаружить проблемы с высоким влиянием"]
ts --> tsf["Помочь в диагностике и исправлении"]
legacy["Inspect.exe и подобные"] -.->|Рекомендуется переход| ai
Рис. 15: У Accessibility Insights три применения — подтвердить, обнаружить и диагностировать, — и это пункт назначения перехода с устаревших инструментов.
8.2. Практическая проверка программой чтения с экрана
То, что автоматическая проверка инструмента может обнаружить, — только проблемы, которые можно судить механически. В конце концов всегда проходите реальную бизнес-операцию с программой чтения с экрана. Встроенный в Windows Narrator можно сразу запустить через Ctrl+клавиша Windows+Enter, а NVDA можно ввести бесплатно.11 Приём проверки — попробовать, не глядя на экран (или с выключенным дисплеем), опираясь только на объявление, можно ли завершить реальную задачу вроде «ввести один заказ и подтвердить его». Проблемы вроде «имя есть, но порядок объявления бессвязный» или фокус, уходящий за пределы модального окна, находятся только на практике.
flowchart TB
accTitle: Сочетание инструментальной проверки и практической
accDescr: То, что автоматическая проверка вроде FastPass может обнаружить, — только проблемы, которые можно судить механически; остальное находится на практике, проходя реальную бизнес-операцию с программой чтения с экрана и находя проблемы порядка объявления и фокуса
tool["Автоматическая проверка инструмента"] --> kikai["Проблемы, которые можно судить механически"]
tool -.-> nokori["Остаются проблемы, которые она не обнаруживает"]
nokori --> sr["Практическая проверка программой чтения"]
sr --> task["Пройти бизнес-операцию"]
task --> mieru["Проблемы порядка объявления и фокуса"]
Рис. 16: Инвентаризируйте механические проблемы автоматической проверкой и находите остальное практической проверкой программой чтения с экрана.
8.3. Встраивание в поток разработки и взаимная окупаемость с автоматическим UI-тестированием
Чтобы проверка не зависела от человека, рекомендуем встроить следующий чек-лист в пункты ревью нового экрана.
| # | Пункт проверки | Средство |
|---|---|---|
| 1 | FastPass с нулём ошибок | Accessibility Insights |
| 2 | У каждого поля ввода и кнопки есть Name | Live Inspect |
| 3 | До каждой функции можно добраться одной клавишей Tab | Вручную |
| 4 | Enter/Esc и основные сочетания работают | Вручную |
| 5 | Коэффициент контраста текста 4,5:1 и выше | Контраст-чекер |
| 6 | Не ломается под темой контраста | Переключить тему и осмотреть визуально |
| 7 | Не ломается при масштабировании 200% | Сменить настройку дисплея и осмотреть визуально |
| 8 | Можно завершить типичную задачу программой чтения | Narrator/NVDA |
И ещё одно. Автоматическое UI-тестирование на FlaUI и подобных построено на той же UIA, которой пользуются программы чтения с экрана. Name и шаблоны, которые вы ставите ради доступности, становятся частями тестового кода, а AutomationId, спроектированный для тестов, облегчает отладку в Live Inspect. Наоборот, интерфейс, который не появляется в дереве UIA, невидим и тестам, и вспомогательным технологиям. Доступность и тестируемость — две стороны одной инвестиции («Автоматическое UI-тестирование десктопных приложений Windows»).
flowchart TB
accTitle: Взаимная окупаемость доступности и автоматического UI-тестирования
accDescr: Программа чтения с экрана и автоматическое UI-тестирование вроде FlaUI построены на одной UIA, поэтому поставленные Name и шаблоны можно использовать с обеих сторон, а интерфейс, который не появляется в дереве UIA, невидим с любой
uia["Навести порядок в дереве UIA"] --> sr["Программа чтения может прочитать"]
uia --> test["Можно использовать в автоматическом UI-тестировании"]
sr -.-> both["Две стороны одной инвестиции"]
test -.-> both
hidden["Интерфейс, которого нет в UIA"] -.-> invisible["Невидим с любой стороны"]
Рис. 17: Поскольку они сидят на одном фундаменте UIA, наведение порядка в дереве UIA окупается и для вспомогательных технологий, и для автоматического UI-тестирования.
9. Как расставлять приоритеты — не чините все экраны сразу
Чинить основную систему из сотен экранов разом нереально и по стоимости, и по качеству. Рекомендуемый подход — следующие три яруса.
- Чините с экранов, которыми этот пользователь пользуется в работе. Разумное приспособление — процесс индивидуального ответа на запрос заинтересованного лица.1 Сначала пусть человек проведёт реальную работу с программой чтения с экрана, и вместе определите, где он застревает. Во многих случаях экраны повседневной работы сужаются до нескольких–десятка, и фатальные проблемы среди них (кнопка без имени, кнопка подтверждения, которую нельзя нажать с клавиатуры) решаются правкой на дни.
- Делайте новую разработку соответствующей стандарту. Добавьте чек-лист главы 8 в Definition of Done и стройте новые экраны поддержанными с самого начала. В отличие от правки задним числом, прирост стоимости встраивания на этапе проектирования невелик.
- Раскатывайте вширь, чиня общие элементы. Если реализовать AccessibleName по умолчанию или AutomationPeer на общих внутренних деталях вроде диалога поиска, сетки или ввода даты, это разом действует на каждый экран, который их использует. Это куда выгоднее, чем трогать отдельные экраны по одному.
flowchart TB
accTitle: Три яруса приоритета исправления
accDescr: Чините с экранов, которыми пользователь пользуется в работе, делайте новую разработку соответствующей стандарту по чек-листу и раскатывайте на каждый экран, чиня общие элементы
s1["1. Чинить с экранов, которыми пользуется пользователь"] --> s2["2. Новая работа соответствует стандарту"] --> s3["3. Раскатать вширь общими элементами"]
s3 -.-> all["Разом действует на каждый экран, который их использует"]
Рис. 18: Продвигайтесь не чиня все экраны сразу, а тремя ярусами: экраны в использовании, новая работа и общие детали.
И запись диалога так же важна, как технический ответ. Разумное приспособление — процесс «индивидуально диалогировать и подстраивать», а не полностью удовлетворять каждый запрос. Рассмотреть альтернативное средство вместе с человеком (сделать эту работу на другом экране, подготовить выгрузку CSV, закрыть операциями) и согласиться, если нагрузка правки слишком тяжела, — тоже законный исход конструктивного диалога.1 Запись того, что было запрошено, на что ответили и что сделали альтернативным средством, становится доказательством добросовестности организации.
flowchart TB
accTitle: Поток конструктивного диалога и записи
accDescr: Отвечайте на запрос лица с инвалидностью через конструктивный диалог; выполняйте правку, на которую можно ответить; для правки, чья нагрузка слишком тяжела, рассмотрите альтернативное средство с человеком и согласитесь; запишите, что было запрошено, на что ответили и что сделали альтернативным средством
req["Запрос"] --> talk["Конструктивный диалог"]
talk --> q{"Нагрузка слишком тяжела?"}
q -->|Нет| kaishu["Ответить правкой"]
q -->|Да| alt["Рассмотреть альтернативу и согласиться"]
kaishu --> rec["Записать историю"]
alt --> rec
Рис. 19: В конструктивном диалоге вы соглашаетесь с человеком на правку или альтернативное средство и оставляете эту историю в записи.
10. Итог
- С изменённым Законом об устранении дискриминации в отношении лиц с инвалидностью, вступившим в силу в апреле 2024 года, предоставление разумного приспособления стало обязанностью и для предприятий. Сфера занятости — обязанность работодателя с 2016 года по Закону о содействии трудоустройству лиц с инвалидностью. Сделать приложение удобнее заранее — «улучшение среды» (обязанность прилагать усилия), и чем дальше оно зашло, тем легче становятся индивидуальные ответы.
- Технические критерии сосредоточены в WCAG (JIS X 8341-3:2016), и то же мышление можно применить к десктопному приложению через WCAG2ICT.
- Программа чтения с экрана читает приложение через UI Automation. Тройка дерева UIA, свойств (Name/ControlType/AutomationId) и шаблонов управления — фундамент.
- Высший приоритет — Name. WinForms использует AccessibleName и привязку Label к порядку табуляции; WPF — AutomationProperties.Name/LabeledBy; пользовательский элемент — AutomationPeer.
- Возможность добраться до каждой функции одной клавиатурой — критерий успеха WCAG и одновременно производительность каждого оператора. Наведите порядок в порядке табуляции, клавишах доступа и индикации фокуса.
- Три основы цвета — коэффициент контраста 4,5:1, цвет не единственное средство и уважение системных цветов в теме контраста.
- Сочетайте проверку FastPass+Live Inspect в Accessibility Insights и практическую проверку Narrator/NVDA и встройте это в поток разработки как чек-лист нового экрана.
- Не чините все экраны сразу; продвигайтесь в порядке экраны, которыми пользуется пользователь → стандартная поддержка новой работы → раскатка вширь общих элементов. Разумное приспособление — процесс диалога, и запись истории защищает организацию.
Как первый шаг рекомендуем взять один из ваших главных экранов, прогнать FastPass в Accessibility Insights for Windows, а затем пройти работу одной клавишей Tab. За тридцать минут нынешнее положение собственного приложения становится удивительно конкретным.
Похожие статьи
- Автоматическое UI-тестирование десктопных приложений Windows — как устроен UI Automation и как строить устойчивые тесты на FlaUI
- UX-проектирование Windows-приложений - приоритеты по средам использования
- Поддержка высокого DPI в WinForms — почему интерфейс размывается или разваливается на 4K-мониторах, и как это исправить
- Высокий DPI в WPF — почему всё «должно быть само в порядке», а на деле размывается и плывёт, и что с этим делать
- Почему KomuraSoft создаёт сайты на дизайн-системе Цифрового агентства Японии — низкая стоимость и качество совместимы
- Ловушки японских шрифтов и символов — как обращаться с JIS2004, IVS и гайдзи в бизнес-приложениях
Смежные области консультирования
KomuraSoft LLC занимается правками доступности бизнес-приложений WinForms/WPF (поддержка программ чтения с экрана, наведение порядка в работе с клавиатуры, поддержка тем контраста), реализацией AutomationPeer на общих элементах и консультациями по диагностике текущего состояния и расстановке приоритетов с Accessibility Insights. Начать со стадии «хотим подтвердить, может ли сотрудник пользоваться нашим приложением с программой чтения с экрана» нормально.
Справочные ссылки
-
Cabinet Office, Leaflet “From 1 April 2024, the provision of reasonable accommodation became an obligation”. О том, что поправка Рэйва 3 к Закону об устранении дискриминации в отношении лиц с инвалидностью вступает в силу 1 апреля Рэйва 6 и предоставление разумного приспособления предприятиями становится обязанностью; о том, что предоставление разумного приспособления — ответ в пределах, не составляющих чрезмерную нагрузку, на выражение намерения лица с инвалидностью; о важности конструктивного диалога и о том, что односторонний отказ может составлять нарушение обязанности; о том, что «улучшение среды», предварительные меры улучшения, направленные на неопределённое число лиц с инвалидностью, — обязанность прилагать усилия; и о том, что занятость и работа следуют положениям Закона о содействии трудоустройству лиц с инвалидностью. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Ministry of Health, Labour and Welfare, The prohibition of discrimination against persons with disabilities in employment and the obligation to provide reasonable accommodation. О том, что изменённый Закон о содействии трудоустройству лиц с инвалидностью, вступивший в силу в апреле Хэйсэй 28, обязывает работодателей запрещать дискриминацию по инвалидности в занятости и предоставлять разумное приспособление в пределах, не составляющих чрезмерную нагрузку; и о связанных материалах вроде руководств по разумному приспособлению. ↩ ↩2 ↩3 ↩4
-
Web Accessibility Infrastructure Committee (WAIC), Understanding JIS X 8341-3:2016. О том, что JIS X 8341-3:2016 — соответствующий стандарт ISO/IEC 40500:2012, и тело стандарта имеет то же содержание, что WCAG 2.0; и об объёме веб-контента, который предполагает стандарт. ↩ ↩2
-
W3C, Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies (WCAG2ICT). О Group Note W3C, которая показывает, как применять принципы, руководства и критерии успеха WCAG 2.0/2.1/2.2 к не-веб-документам и ПО. ↩ ↩2
-
Microsoft Learn, UI Automation Specification. О том, что UI Automation предоставляет информацию об интерфейсе вспомогательным технологиям вроде программы чтения с экрана и позволяет управлять средствами, отличными от стандартного ввода; и о составе элементов UIA, дерева, свойств, шаблонов управления, типов элементов и событий. ↩ ↩2 ↩3
-
Microsoft Learn, WinForms: Setting the accessible name on a control. О том, что Text переиспользуется как UIA Name на некоторых элементах, тогда как ComboBox, ListBox, ListView, PictureBox, ProgressBar, TabControl, TextBox, TreeView и подобные его не переиспользуют; о постановке целевого элемента сразу после TabIndex Label, чтобы текст Label использовался как Name; и о явном задании AccessibleName и проблеме пустой строки, остающейся в файле дизайнера. ↩ ↩2 ↩3 ↩4
-
W3C / Web Accessibility Infrastructure Committee (WAIC) translation, Web Content Accessibility Guidelines (WCAG) 2.1 Japanese translation. О критерии успеха 1.4.3 (Contrast (Minimum)) 4,5:1 для текста и 3:1 для крупного текста; о критерии успеха 1.4.1 (Use of Color) не делать цвет единственным визуальным средством; и о критерии успеха 2.1.1 (Keyboard) клавиатурной управляемости всей функциональности. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Contrast themes. О том, что темы контраста используют ограниченную палитру с коэффициентом контраста в целом 7:1 и выше; о выборе встроенной темы и правке цветов; и о том, что ресурсы класса SystemColor определены как пары передний план/фон и автоматически следуют смене темы. ↩ ↩2 ↩3
-
Microsoft Learn, Accessibility testing. О трёх сценариях Accessibility Insights for Windows — Live Inspect (подтверждение свойств UIA наведением/фокусом), FastPass (обнаружение проблем с высоким влиянием менее чем за пять минут) и Troubleshooting — и о рекомендации перейти с устаревших инструментов вроде Inspect и AccEvent. ↩ ↩2 ↩3
-
NVDA Japanese Team, NVDA Japanese edition. О свободной программе чтения с экрана Windows с открытым исходным кодом NVDA и о предоставлении её японского издания. ↩ ↩2
-
Microsoft Learn, Walkthrough: Creating an Accessible Windows-based Application. О постановке описательной Label в непосредственно предшествующем порядке табуляции поля ввода; о клавише доступа через & в Text; об определении высокой контрастности через SystemInformation.HighContrast и использовании SystemColors; об отслеживании события UserPreferenceChanged; и о сочетании визуального намёка с информацией, передаваемой цветом. ↩ ↩2 ↩3
-
Microsoft Learn, Providing Accessibility Information for Controls. О свойствах AccessibleName, AccessibleDescription, AccessibleRole и AccessibleDefaultActionDescription элемента WinForms и о том, как их задавать. ↩
-
Microsoft Learn, WPF: Setting the accessible name on an edit field. О том, что Text у TextBlock переиспользуется как UIA Name, тогда как Text у TextBox выставляется как UIA Value; и о связывании метки-TextBlock с TextBox через AutomationProperties.LabeledBy или задании AutomationProperties.Name. ↩
-
Microsoft Learn, UI Automation of a WPF Custom Control. О том, что пользовательский элемент переопределяет OnCreateAutomationPeer и возвращает класс, производный от AutomationPeer; о наследовании класса Peer, соответствующего базовому элементу; о предоставлении провайдера шаблона через GetPattern; и о переопределении со стороны XAML атрибутами AutomationProperties. ↩ ↩2
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Автоматическое UI-тестирование десктопных приложений Windows — как устроен UI Automation и как строить устойчивые тесты на FlaUI
Разбираем автоматическое UI-тестирование WinForms/WPF-приложений от основ Windows UI Automation. Минимальная реализация на FlaUI, проекти...
Что на самом деле значит «Не отвечает» — как Windows решает, что приложение зависло, и как проектировать приложения, которые не зависают
«Не отвечает» в Windows — механизм, в котором ОС судит, что окно не извлекало сообщение 5 секунд, и подменяет его окном-призраком. Статья...
Как работают буфер обмена и перетаскивание — правильная обработка OLE-передачи данных в бизнес-приложениях
Вставляете таблицу Excel — и оформление разваливается; закрываете исходное приложение — и вставить больше нельзя: оба случая от того, что...
Встраиваем аутентификацию Entra ID в приложения WinForms/WPF — практическая архитектура на MSAL.NET и брокере WAM
Разбираем порядок встраивания аутентификации Entra ID в десктопные приложения WinForms/WPF: концепцию публичного клиента, регистрацию при...
После IE-режима — WebView2? Ограничение по ActiveX и реалистичный план миграции
Разбираем базовую архитектуру WebView2, стратегии распространения Evergreen и Fixed Version, ловушку с папкой пользовательских данных, сп...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Поток UI и таймеры
Поток UI WPF / WinForms, асинхронные операции, Dispatcher и проектирование таймеров.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Обязательна ли поддержка доступности бизнес-приложения по закону?
- Поправка 2021 года к Закону об устранении дискриминации в отношении лиц с инвалидностью вступила в силу 1 апреля 2024 года, и предоставление разумного приспособления лицам с инвалидностью стало обязанностью и для предприятий. Разумное приспособление — это ответ, который по запросу лица с инвалидностью снимает индивидуальный барьер в пределах, не составляющих чрезмерную нагрузку; сделать приложение удобнее заранее позиционируется как обязанность прилагать усилия, называемая «улучшением среды». Занятость, например отношение между сотрудником и компанией, регулируется не этим законом, а Законом о содействии трудоустройству лиц с инвалидностью, который обязал работодателей предоставлять разумное приспособление с поправки, вступившей в силу в апреле 2016 года. Иначе говоря, ситуация «сотрудник не может пользоваться бизнес-приложением» уже давно в зоне обязанности. Насколько далеко идти в конкретном случае, зависит от индивидуальной ситуации, поэтому сверяйтесь с первичными источниками Кабинета министров и Министерства здравоохранения, труда и социального обеспечения и решайте в диалоге с заинтересованным лицом.
- Как программа чтения с экрана читает десктопное приложение Windows?
- Программы чтения с экрана вроде Narrator и NVDA читают интерфейс приложения через фундамент доступности под названием UI Automation (UIA). Сторона приложения выставляет элементы на экране в структуре, называемой деревом UIA; у каждого элемента есть свойства вроде Name (назначение) и ControlType (вид), и шаблоны управления вроде Invoke (нажать) и Value (значение). Программа чтения объявляет эту информацию как «кнопка Подтвердить заказ» и действует через шаблоны. Стандартные элементы WinForms и WPF имеют этот механизм с самого начала, поэтому главная работа разработчика — не оставлять Name пустым, сделать интерфейс управляемым с клавиатуры и реализовать информацию на пользовательских элементах.
- В существующем приложении WinForms с чего начать?
- Кратчайший путь — прогнать FastPass в Accessibility Insights for Windows по целевому экрану и инвентаризировать элементы с пустым Name и проблемы порядка табуляции. Исправления начинают с задания AccessibleName на кнопках только с иконкой, привязки Label в непосредственно предшествующем порядке табуляции поля ввода и приведения TabIndex в соответствие с визуальным порядком. Затем запустите Narrator или NVDA и пройдите реальную бизнес-операцию, не глядя на экран, и подтвердите, где вы застреваете. Не нужно чинить все экраны сразу; начинать с экранов, которыми кто-то реально пользуется, и делать новые экраны соответствующими чек-листу — реалистично.
- Что делать для поддержки высокой контрастности (темы контраста)?
- База — не зашивать цвета жёстко и уважать системные цвета. В WinForms оставляйте ForeColor/BackColor по умолчанию или используйте SystemColors, определяйте состояние через SystemInformation.HighContrast и отслеживайте переключение событием UserPreferenceChanged. В WPF и WinUI тоже, если ссылаетесь на ресурсы класса SystemColors, вы автоматически следуете смене темы. Одновременно перестаньте передавать информацию «одним только цветом» — показывать ошибку только красным — и сочетайте её с иконкой или формулировкой. Даже в обычной теме ориентир WCAG на коэффициент контраста текста 4,5:1 и выше делает интерфейс читаемее и для плохо освещённого цеха, и для более старших пользователей.
- Помогает ли поддержка доступности ещё и автоматическому UI-тестированию?
- Да. Инструменты автоматического UI-тестирования вроде FlaUI построены на той же UI Automation, которой пользуются программы чтения с экрана. Name, ControlType и шаблоны управления, которые вы ставите ради доступности, можно использовать как есть из тестового кода, а AutomationId, спроектированный для тестов, стабилизирует идентификацию элементов. Наоборот, пользовательски нарисованный интерфейс, который не появляется в дереве UIA, невидим и программе чтения, и тестам. Доступность и автоматическое тестирование — инвестиция в один и тот же фундамент, поэтому постановка любого из них снижает и стоимость другого.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.