Модель автоматизации пользовательского интерфейса пользовательского элемента управления WPF
Модель автоматизации пользовательского интерфейса Майкрософт предоставляет единый общий интерфейс, который клиенты могут использовать для проверки или использования пользовательских интерфейсов различных платформ и инфраструктур автоматизации. Автоматизация пользовательского интерфейса обеспечивает проверку кода качества (тестирования), так и приложениями со специальными возможностями, такие как средства чтения с экрана для проверки элементов пользовательского интерфейса и моделирования пользовательского взаимодействия с ними из другого кода. Сведения о Автоматизация пользовательского интерфейса на всех платформах см. в разделе, посвященном специальным возможностям.
В этом разделе описывается реализация серверного поставщика автоматизации пользовательского интерфейса для пользовательского элемента управления, применяемого в приложении WPF. WPF поддерживает Автоматизация пользовательского интерфейса с помощью дерева одноранговых объектов автоматизации, которое сопутствует дереву элементов интерфейса пользователя. Тестовый код и приложения с поддержкой специальных возможностей могут использовать одноранговые объекты автоматизации напрямую (для внутрипроцессного кода) или через универсальный интерфейс, предоставляемый Автоматизация пользовательского интерфейса.
Одноранговые классы автоматизации
Элементы управления WPF поддерживают Автоматизация пользовательского интерфейса посредством дерева одноранговых классов, производных от AutomationPeer. В соответствии с соглашением имена одноранговых классов начинаются с имени класса элемента управления, к которому добавляется строка "AutomationPeer". Например ButtonAutomationPeer — это одноранговый класс для Button класс элемента управления. Одноранговые классы примерно похожи на типы элементов управления Автоматизация пользовательского интерфейса, но относятся к элементам WPF. Код автоматизации, обращающийся к приложениям WPF через интерфейс Автоматизация пользовательского интерфейса, не использует одноранговые классы автоматизации напрямую, но код автоматизации в том же пространстве процесса может использовать их напрямую.
Встроенные одноранговые классы автоматизации
Элементы реализуют одноранговый класс автоматизации, если они принимают взаимодействие пользователя с интерфейсом или содержат информацию, необходимую пользователям приложений для чтения с экрана. Не все визуальные элементы WPF имеют одноранговые классы автоматизации. Примеры классов, реализующих одноранговые объекты автоматизации: Button, TextBox, и Label. Примерами классов, не реализующих одноранговые объекты автоматизации являются классами, производными от Decorator, такие как Borderи классы, основанные на Panel, такие как Grid и Canvas.
Базовый Control класс не имеет соответствующего однорангового класса. Если требуется, чтобы одноранговый класс соответствовал пользовательскому элементу управления, производный от Control, необходимо создать производный класс пользовательского однорангового FrameworkElementAutomationPeer.
Вопросы безопасности для производных одноранговых классов
Одноранговые классы автоматизации должны работать в среде с частичным доверием. Код в сборке UIAutomationClient не настроен для выполнения в среде с частичным доверием и код однорангового класса автоматизации не должен ссылаться на эту сборку. Вместо этого следует использовать классы в сборке UIAutomationTypes. Например, следует использовать AutomationElementIdentifiers класса из сборки UIAutomationTypes, который соответствует AutomationElement класс в сборке UIAutomationClient. В коде однорангового класса автоматизации можно безопасно ссылаться на сборку UIAutomationTypes.
Навигация по одноранговым объектам
После обнаружения однорангового объекта автоматизации, внутрипроцессный код может перемещаться по дереву одноранговых путем вызова объекта GetChildren и GetParent методы. Перемещение между WPF элементов в элементе управления поддерживается реализацией однорангового узла GetChildrenCore метод. Система модели автоматизации пользовательского интерфейса вызывает этот метод для построения дерева подэлементов, содержащихся в элементе управления (например, элементов списка в элементе управления "список" (ListBox)). Значение по умолчанию UIElementAutomationPeer.GetChildrenCore метод обходит визуальное дерево элементов для построения дерева одноранговых объектов автоматизации. Пользовательские элементы управления переопределяют этот метод для предоставления дочерних элементов клиентам автоматизации, возвращая одноранговые объекты автоматизации элементов, которые передают информацию или разрешают взаимодействие с пользователем.
Настройка производного однорангового класса
Все классы, производные от UIElement и ContentElement содержат защищенный виртуальный метод OnCreateAutomationPeer. WPF вызывает OnCreateAutomationPeer для получения однорангового объекта автоматизации для каждого элемента управления. Код автоматизации может использовать одноранговый объект для получения информации о характеристиках и функциях элемента управления и моделирования интерактивного использования. Пользовательский элемент управления, поддерживающий автоматизацию необходимо переопределить OnCreateAutomationPeer и возвращать экземпляр класса, производного от AutomationPeer. Например, если пользовательский элемент управления является производным от ButtonBase класса, то объект, возвращенный OnCreateAutomationPeer должен быть производным от ButtonBaseAutomationPeer.
При реализации пользовательского элемента управления необходимо переопределить методы "Core" базового однорангового класса автоматизации, которые описывают специфическое поведение пользовательского элемента управления.
Переопределение метода OnCreateAutomationPeer
Переопределить OnCreateAutomationPeer метод для пользовательского элемента управления так, чтобы он возвращал объект поставщика, который должен прямо или косвенно наследующие от AutomationPeer.
Переопределение метода GetPattern
Одноранговые классы автоматизации упрощают некоторые аспекты реализации поставщиков Автоматизация пользовательского интерфейса на стороне сервера, но одноранговые классы автоматизации пользовательских элементов управления по-прежнему должны обрабатывать интерфейсы шаблонов. Как и поставщиках, отличных от WPF, одноранговые классы поддерживают шаблоны элементов управления, предоставляя реализации интерфейсов в System.Windows.Automation.Provider пространства имен, такие как IInvokeProvider. Интерфейсы шаблонов элементов управления могут быть реализованы самим одноранговым классом или другим объектом. Реализация однорангового узла GetPattern возвращает объект, который поддерживает указанный шаблон. Автоматизация пользовательского интерфейса код вызывает GetPattern метода с указанием PatternInterface значение перечисления. Переопределенный GetPattern должен возвращать объект, который реализует заданный шаблон. Если элемент управления не имеет пользовательской реализации шаблона, можно вызвать реализацию базового типа GetPattern для извлечения его реализации или значение null, если шаблон не поддерживается для данного типа элемента управления. Например, пользовательский элемент управления NumericUpDown может быть присвоено значение в диапазоне, поэтому его Автоматизация пользовательского интерфейса одноранговый IRangeValueProvider интерфейс. В следующем примере показан способ однорангового узла GetPattern метод переопределяется, чтобы реагировать на них PatternInterface.RangeValue значение.
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPattern(patternInterface);
}
Объект GetPattern метод также может указывать подэлемент в качестве поставщика шаблона. В следующем коде показано, как ItemsControl передает обработку шаблона в одноранговый своих внутренних прокрутки ScrollViewer элемента управления.
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Scroll)
{
ItemsControl owner = (ItemsControl) base.Owner;
// ScrollHost is internal to the ItemsControl class
if (owner.ScrollHost != null)
{
AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
if ((peer != null) && (peer is IScrollProvider))
{
peer.EventsSource = this;
return (IScrollProvider) peer;
}
}
}
return base.GetPattern(patternInterface);
}
Public Class Class1
Public Overrides Function GetPattern(ByVal patternInterface__1 As PatternInterface) As Object
If patternInterface1 = PatternInterface.Scroll Then
Dim owner As ItemsControl = DirectCast(MyBase.Owner, ItemsControl)
' ScrollHost is internal to the ItemsControl class
If owner.ScrollHost IsNot Nothing Then
Dim peer As AutomationPeer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost)
If (peer IsNot Nothing) AndAlso (TypeOf peer Is IScrollProvider) Then
peer.EventsSource = Me
Return DirectCast(peer, IScrollProvider)
End If
End If
End If
Return MyBase.GetPattern(patternInterface1)
End Function
End Class
Чтобы указать подэлемент для обработки шаблона, этот код получает объект подэлемента, создает одноранговый объект с помощью CreatePeerForElement задает метод, EventsSource свойства нового однорангового текущему одноранговому узлу и возвращает новый одноранговый элемент. Установка EventsSource на подэлемент подэлементе предотвращает появление в дереве одноранговых классов автоматизации и определяет все события, вызванные вложенного элемента как исходящие из элемента управления, указанного в EventsSource. ScrollViewer Управления не отображается в дереве модели автоматизации, а события прокрутки, которые она создает выглядят как исходящие от ItemsControl объекта.
Переопределение методов "Core"
Код автоматизации получает информацию о вашем элементе управления, вызывая открытые методы однорангового класса. Чтобы предоставить информацию о своем элементе управления, переопределите все методы, имена которых заканчиваются на "Core", если ваша реализация элемента управления отличается от той, которая имеется в базовом одноранговом классе автоматизации. Как минимум, необходимо реализовать GetClassNameCore и GetAutomationControlTypeCore методы, как показано в следующем примере.
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
Реализация GetAutomationControlTypeCore описывает ваш элемент управления, возвращая ControlType значение. Хотя вы можете вернуть ControlType.Custom, следует возвращать один более конкретные типы элементов управления, если он точно описывает ваш элемент управления. Возвращаемое значение, равное ControlType.Custom требует дополнительной работы поставщика, чтобы реализовать Автоматизация пользовательского интерфейса, и Автоматизация пользовательского интерфейса клиентские продукты не могут предвидеть структуру элемента управления, взаимодействие с клавиатурой и возможных шаблонах элементов управления.
Реализуйте IsContentElementCore и IsControlElementCore методов для обозначения ли элемент управления содержимым данных или выполняет интерактивную роль в пользовательском интерфейсе (или оба). По умолчанию оба метода возвращают значение true
. Эти параметры повышают удобство использования средств автоматизации (например, средств чтения с экрана), которые могут использовать эти методы для фильтрации дерева автоматизации. Если ваш GetPattern метод передает обработку шаблона в одноранговый объект подэлемента однорангового элемента IsControlElementCore метод может возвращать значение false, чтобы скрыть одноранговый узел подэлемента в дереве автоматизации. Например, прокрутка в ListBox обрабатывается ScrollViewerи одноранговый элемент автоматизации для PatternInterface.Scroll возвращается GetPattern метод ScrollViewerAutomationPeer , связанный с ListBoxAutomationPeer. Таким образом IsControlElementCore метод ScrollViewerAutomationPeer возвращает false
, так что ScrollViewerAutomationPeer не отображается в дереве модели автоматизации.
Одноранговый класс автоматизации должен предоставлять необходимые значения по умолчанию для вашего элемента управления. Обратите внимание, что XAML, который ссылается на элемент управления может переопределить реализации базовых методов путем включения AutomationProperties атрибуты. Например, следующий код XAML создает кнопку, которая имеет два настраиваемых свойства Автоматизация пользовательского интерфейса.
<Button AutomationProperties.Name="Special"
AutomationProperties.HelpText="This is a special button."/>
Реализация поставщиков шаблонов
Интерфейсы, реализованные с помощью пользовательского поставщика, объявляются явно в том случае, если элемент-владелец является производным непосредственно от Control. Например, в следующем коде объявляется одноранговый объект для объекта Control , реализующий значение диапазона.
public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }
Public Class RangePeer1
Inherits FrameworkElementAutomationPeer
Implements IRangeValueProvider
End Class
Владелец-элемент управления, производного от определенного типа элемента управления, такие как RangeBase, одноранговый узел может быть производным от эквивалентного производного однорангового класса. В этом случае одноранговый узел будет наследовать от класса RangeBaseAutomationPeer, который предоставляет базовую реализацию IRangeValueProvider. В следующем коде показано объявление такого однорангового класса.
public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
Inherits RangeBaseAutomationPeer
End Class
Пример реализации см. в разделе Пример пользовательского элемента управления NumericUpDown с темой и поддержкой модели автоматизации пользовательского интерфейса.
Создание событий
Клиенты автоматизации могут подписаться на события автоматизации. Пользовательские элементы управления должны сообщать об изменениях для управления состоянием, вызвав RaiseAutomationEvent метод. Аналогично, при изменении значения свойства следует вызывать RaisePropertyChangedEvent метод. В приведенном ниже коде показано, как получить одноранговый объект из кода элемента управления и вызвать метод для создания события. В качестве меры оптимизации код также определяет, имеются ли прослушиватели для этого типа событий. Создание событий только при наличии соответствующих прослушивателей позволяет избежать лишней нагрузки и помогает сохранять должную скорость отклика элемента управления.
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}