Настраиваемые одноранговые элементы автоматизации

Описывает концепцию одноранговых элементов автоматизации для модели автоматизации пользовательского интерфейса Microsoft, а также способы обеспечения поддержки автоматизации для вашего собственного настраиваемого класса пользовательского интерфейса.

Модель автоматизации пользовательского интерфейса обеспечивает схему, которую могут использовать клиенты автоматизации для проверки или работы пользовательских интерфейсов различных платформ и структур. Если вы пишете приложение для Windows, классы, используемые для пользовательского интерфейса, уже обеспечивают поддержку автоматизации пользовательского интерфейса. Чтобы определить новый вид элемента управления пользовательского интерфейса или класса поддержки, можно использовать наследование от существующих незапечатанных классов. В ходе этого процесса ваш класс может добавить поведение, которое должно иметь поддержку специальных возможностей, не включенную в состав модели автоматизации пользовательского интерфейса по умолчанию. В этом случае следует расширить существующую поддержку автоматизации пользовательского интерфейса, наследуя его от класса AutomationPeer , используемого базовой реализацией, добавив необходимую поддержку в одноранговую реализацию и уведомив инфраструктуру управления приложениями Windows о том, что она должна создать новый одноранговый узел.

Модель автоматизации пользовательского интерфейса обеспечивает не только работу приложений со специальными возможностями и вспомогательных технологий, таких как программы чтения с экрана, но и выполнение кода обеспечения (тестирования) качества. В любом случае клиенты автоматизации пользовательского интерфейса могут изучать элементы пользовательского интерфейса и моделировать взаимодействие пользователя с приложением на основе другого кода, не относящегося к приложению. Сведения о модели автоматизации пользовательского интерфейса для всех платформ и более подробное описание см. в разделе с общими сведениями о модели автоматизации пользовательского интерфейса.

Существует две группы, которые используют инфраструктуру автоматизации пользовательского интерфейса.

  • Клиенты автоматизации пользовательского интерфейса вызывают API модели автоматизации пользовательского интерфейса, чтобы узнать, какие элементы пользовательского интерфейса отображаются для пользователя в данный момент. Например, такая вспомогательная технология, как программа чтения с экрана, действует в качестве клиента автоматизации пользовательского интерфейса. Пользовательский интерфейс представлен в виде дерева связанных между собой элементов автоматизации. Клиент автоматизации пользовательского интерфейса может быть заинтересован только в одном приложении или сразу во всем дереве. Клиент автоматизации пользовательского интерфейса может использовать API модели автоматизации пользовательского интерфейса для навигации по дереву и считывания или изменения сведений в элементах автоматизации.
  • Поставщики автоматизации пользовательского интерфейса передают информацию дереву автоматизации пользовательского интерфейса путем реализации API, воздействующих на элементы в пользовательском интерфейсе, который они представляют как часть своего приложения. Теперь, создавая новый элемент управления, вы должны выступать как участник в сценарии поставщика автоматизации пользовательского интерфейса. В качестве поставщика вы должны обеспечить всем клиентам автоматизации пользовательского интерфейса возможность использовать инфраструктуру автоматизации пользовательского интерфейса для взаимодействия с вашим элементом управления с целью предоставления специальных возможностей и для проверки.

Обычно в инфраструктуре автоматизации пользовательского интерфейса есть параллельные API: один API для клиентов модели автоматизации пользовательского интерфейса и другой API с похожим именем для поставщиков модели автоматизации пользовательского интерфейса. Данный раздел посвящен в большей мере API для поставщиков автоматизации пользовательского интерфейса, а именно классам и интерфейсам, которые предоставляют расширение поставщика в данной инфраструктуре пользовательского интерфейса. Периодически мы будем упоминать API, которые используют клиенты автоматизации пользовательского интерфейса, чтобы дать общее представление или предоставить обзорную таблицу соответствия API клиентов и поставщиков. Подробнее с точки зрения клиента см. в разделе с руководством по программированию клиента автоматизации пользовательского интерфейса.

Примечание

Клиенты автоматизации пользовательского интерфейса обычно не используют управляемый код и не реализуются в виде приложений UWP (они, как правило, являются классическими приложениями). Модель автоматизации пользовательского интерфейса основывается на стандартной, неспециальной реализации или инфраструктуре. Многие существующие клиенты автоматизации пользовательского интерфейса, включая продукты для специальных возможностей — например, средства чтения с экрана, — используют интерфейсы модели COM для взаимодействия с моделью автоматизации пользовательского интерфейса, системой и приложениями, выполняющимися в дочерних окнах. Подробнее об интерфейсах модели COM и о том, как написать клиент автоматизации пользовательского интерфейса, используя модель COM, см. в разделе Основы модели автоматизации пользовательского интерфейса.

Определение существующего состояния поддержки модели автоматизации пользовательского интерфейса для настраиваемого класса пользовательского интерфейса

Прежде чем пытаться реализовать одноранговый элемент автоматизации для пользовательского элемента управления, следует проверить, не обеспечивают ли уже базовый класс и его одноранговый элемент автоматизации необходимые специальные возможности или поддержку автоматизации. Во многих случаях сочетание реализаций FrameworkElementAutomationPeer, конкретных одноранговых элементов и шаблонов, которые они реализуют, может обеспечить базовые, но приемлемые специальные возможности. Истинность данного утверждения зависит от того, сколько изменений внесено в степень воздействия элемента управления на модель объекта по сравнению с базовым классом. Кроме того, это зависит от соответствия ваших дополнений к функциям базового класса новым элементам пользовательского интерфейса в шаблоне контракта или внешнему виду элемента управления. В некоторых случаях ваши изменения могут ввести новые аспекты взаимодействия с пользователем, которые требуют дополнительной поддержки специальных возможностей.

Даже если при использовании текущего базового однорангового класса обеспечивается базовая поддержка специальных возможностей, рекомендуется определить одноранговый элемент таким образом, чтобы можно было сообщать точные сведения о ClassName модели автоматизации пользовательского интерфейса для сценариев автоматической проверки. Это особенно важно, если вы создаете элемент управления для стороннего потребления.

Классы одноранговых элементов автоматизации

UWP основывается на существующих методах автоматизации пользовательского интерфейса и соглашениях, используемых в предыдущих инфраструктурах пользовательского интерфейса с управляемым кодом, например Windows Forms, Windows Presentation Foundation (WPF) и Microsoft Silverlight. Многие классы элементов управления, их функции и цели также происходят из предыдущей инфраструктуры пользовательского интерфейса.

В соответствии с соглашением имена одноранговых классов начинаются с имени класса элемента управления, к которому добавляется строка "AutomationPeer". Например, ButtonAutomationPeer — это одноранговый класс для класса элемента управления Button.

Примечание

В рамках этого раздела при реализации однорангового элемента управления мы будем уделять особое внимание свойствам, связанным со специальными возможностями. Но для более общей концепции поддержки модели автоматизации пользовательского интерфейса необходимо реализовать одноранговый элемент в соответствии с рекомендациями, приведенными в руководстве по программированию поставщика модели автоматизации пользовательского интерфейса и разделе об основах модели автоматизации пользовательского интерфейса. В этих разделах не рассматриваются конкретные API AutomationPeer, с помощью которых предоставляются сведения в инфраструктуре UWP для модели автоматизации пользовательского интерфейса, но в них описаны свойства, которые идентифицируют ваш класс или представляют другие сведения и взаимодействия.

Одноранговые элементы, шаблоны и типы элементов управления

Шаблон элемента управления представляет собой реализацию интерфейса, который предоставляет конкретный аспект функциональности элемента управления для клиентов автоматизации пользовательского интерфейса. Клиенты автоматизации пользовательского интерфейса используют свойства и методы, предоставляемые через шаблон элемента управления, для получения сведений о возможностях элемента управления или для манипулирования реакцией элемента управления на события во время выполнения.

Шаблоны элементов управления позволяют классифицировать и предоставлять функции элемента управления независимо от типа или внешнего вида элемента управления. Например, элемент управления, который представляет табличный интерфейс, использует шаблон элемента управления Grid для отображения количества строк и столбцов в таблице и для включения клиента модели автоматизации пользовательского интерфейса с целью извлечения элементов из таблицы. Другой пример: клиент модели автоматизации пользовательского интерфейса может использовать шаблон элемента управления Invoke для элементов управления, которые могут быть вызваны (например, кнопок), и шаблон элемента управления Scroll для элементов управления, которые имеют полосы прокрутки, например списков, представлений списков или полей со списком. Каждый шаблон элемента управления представляет собой отдельный тип функциональности, поэтому шаблоны элементов управления можно объединить для описания полного набора функциональных возможностей, поддерживаемых определенным элементом управления.

Шаблоны элемента управления относятся к пользовательскому интерфейсу так же, как интерфейсы относятся к объектам модели COM. В модели COM вы можете запросить у объекта сведения о поддерживаемых им интерфейсах, а затем использовать эти интерфейсы, чтобы получить доступ к функциональности. В модели автоматизации пользовательского интерфейса клиенты автоматизации пользовательского интерфейса могут запросить у элемента автоматизации пользовательского интерфейса сведения о поддерживаемых им шаблонах, а затем начать взаимодействие с элементом посредством свойств, методов, событий и структур, предоставленных поддерживаемыми шаблонами элемента управления.

Одна из главных целей однорангового элемента автоматизации — сообщить клиенту автоматизации пользовательского интерфейса о том, какие шаблоны управления может поддерживать элемент пользовательского интерфейса с помощью своего однорангового элемента. Для этого поставщики модели автоматизации пользовательского интерфейса реализуют новые одноранговые элементы, изменяющие поведение метода GetPattern путем переопределения метода GetPatternCore. Клиенты модели автоматизации пользовательского интерфейса выполняют вызовы, которые поставщик модели автоматизации пользовательского интерфейса сопоставляет с вызовом метода GetPattern. Клиенты модели автоматизации пользовательского интерфейса запрашивают каждый конкретный шаблон, с которым они хотят взаимодействовать. Если одноранговый элемент поддерживает этот шаблон, то он возвращает объектную ссылку на самого себя, в противном случае он возвращает значение null. Если возвращаемое значение не равно null, то клиент модели автоматизации пользовательского интерфейса ожидает, что он может вызвать API интерфейса шаблона как клиент для взаимодействия с этим шаблоном элемента управления.

Тип элемента управления позволяет в общем виде задать возможности элемента управления, представляемого одноранговым элементом. Понятие типа отличается от шаблона элемента управления, поскольку шаблон сообщает модели автоматизации пользовательского интерфейса о данных, которые он может получать, или о действиях, которые он может выполнять посредством определенного интерфейса, а тип элемента управления находится на уровень выше. В каждом типе элемента управления даются рекомендации по следующим аспектам модели автоматизации пользовательского интерфейса.

  • Шаблоны элементов управления для автоматизации пользовательского интерфейса. Тип элемента управления может поддерживать несколько шаблонов, каждый из которых представляет собственную классификацию информации или отдельное взаимодействие. Каждый тип элемента управления содержит набор шаблонов элемента управления, которые должен поддерживать элемент управления, набор необязательных шаблонов и набор шаблонов, которые элемент управления не должен поддерживать.
  • Значения свойств автоматизации пользовательского интерфейса. Каждый тип элемента управления содержит набор свойств, которые должен поддерживать элемент управления. Это общие свойства, описанные в обзоре свойств автоматизации пользовательского интерфейса, а не свойства, зависящие от шаблона.
  • События автоматизации пользовательского интерфейса. Каждый тип элемента управления содержит набор событий, которые должен поддерживать элемент управления. Эти события также не зависят от шаблона, как описано в обзоре событий автоматизации пользовательского интерфейса.
  • Дерево автоматизации пользовательского интерфейса. Каждый тип элемента управления определяет порядок отображения элемента управления в дереве автоматизации пользовательского интерфейса.

Независимо от того, как реализуются одноранговые элементы автоматизации для инфраструктуры, функциональность клиента модели автоматизации пользовательского интерфейса не привязана к платформе UWP. Более того, весьма вероятно, что в существующих клиентах модели автоматизации пользовательского интерфейса, таких как специальные возможности, будут использоваться другие модели программирования, например модель COM. В модели COM клиенты могут создавать запросы QueryInterface для интерфейса шаблонов элементов управления модели COM, в котором реализуется запрошенный шаблон, или изучать свойства, события и древовидную структуру общей инфраструктуры автоматизации пользовательского интерфейса. Для шаблонов инфраструктура автоматизации пользовательского интерфейса маршалирует код интерфейса в код платформы UWP, предназначенный для поставщика автоматизации пользовательского интерфейса приложения и соответствующего однорангового элемента.

При реализации шаблонов элементов управления для платформы с управляемым кодом, такой как приложение UWP с помощью C# или Microsoft Visual Basic, вы можете использовать интерфейсы платформа .NET Framework для представления этих шаблонов вместо представления COM-интерфейса. Например, интерфейс шаблона модели автоматизации пользовательского интерфейса для реализации шаблона Invoke поставщиком Microsoft .NET — IInvokeProvider.

Список шаблонов элементов управления, интерфейсов поставщика и их назначение см. в разделе Шаблоны и интерфейсы элементов управления. Список типов элементов управления см. в разделе Обзор типов элементов управления для автоматизации пользовательского интерфейса.

Рекомендации по реализации шаблонов элементов управления

Шаблоны элементов управления и их назначение входят в более масштабное определение инфраструктуры автоматизации пользовательского интерфейса и не относятся только к поддержке специальных возможностей в приложении UWP. При реализации шаблона элемента управления необходимо убедиться, что он реализуется таким образом, чтобы он соответствовал рекомендациям, описанным в этих документах, а также в спецификации автоматизации пользовательского интерфейса. Если вы ищете рекомендации, вы можете использовать документацию Майкрософт, и вам не нужно будет ссылаться на спецификацию. Рекомендации по каждому шаблону приведены в разделе, посвященном реализации шаблонов элементов управления для автоматизации пользовательского интерфейса. В каждом разделе этой области есть подразделы "Рекомендации и соглашения по реализации" и "Обязательные члены". В рекомендациях обычно упоминаются конкретные API соответствующего интерфейса шаблона элемента управления в справочнике Интерфейсы шаблонов элементов управления для поставщиков. Это собственные интерфейсы или COM-интерфейсы (и в их API используется синтаксис в стиле COM). Для всех показанных элементов есть эквивалент в пространстве имен Windows.UI.Xaml.Automation.Provider.

Если вы используете одноранговые элементы автоматизации по умолчанию и расширяете их возможности, то эти элементы уже написаны в соответствии с рекомендациями по модели автоматизации пользовательского интерфейса. Если они поддерживают шаблоны элементов управления, то вы можете быть уверены, что эта поддержка соответствует рекомендациям из раздела, посвященного реализации шаблонов элементов управления для автоматизации пользовательского интерфейса. Если одноранговый элемент для элемента управления сообщает, что он представляет тип элемента управления, определенный в модели автоматизации пользовательского интерфейса, то в этом одноранговом элементе соблюдаются рекомендации, описанные в разделе Поддержка типов элементов управления для автоматизации пользовательского интерфейса.

Чтобы обеспечить соответствие рекомендациям по автоматизации пользовательского интерфейса в реализации вашего однорангового элемента, вам все же могут понадобиться дополнительные указания по шаблонам или типам элементов управления. Это особенно актуально в случае, когда вы реализуете поддержку шаблона или типа элемента управления, которая не обеспечивается в реализации по умолчанию для элемента управления UWP. Например, ни в одном из элементов управления XAML по умолчанию не реализован шаблон для заметок. Если в вашем приложении активно используются заметки, вам может понадобиться обеспечить специальные возможности для заметок. В таком сценарии ваш одноранговый элемент должен реализовать интерфейс IAnnotationProvider и, вероятно, также сообщать, что он является типом элемента управления Document со свойствами, которые будут указывать, что документы поддерживают заметки.

В качестве ориентира и общего руководства рекомендуется использовать указания для шаблонов из раздела, посвященного реализации шаблонов элементов управления модели автоматизации пользовательского интерфейса, или указания для типов элементов управления из раздела о поддержке типов элементов управления модели автоматизации пользовательского интерфейса. Возможно, следует изучить описание некоторых API по ссылкам, уделив внимание примечаниям об их назначении. Чтобы найти конкретный синтаксис, необходимый для программирования приложений UWP, определите эквивалентный API в пространстве имен Windows.UI.Xaml.Automation.Provider и получите дополнительную информацию на справочных страницах.

Встроенные классы одноранговых элементов автоматизации

В целом элементы реализуют класс одноранговых элементов автоматизации, если они принимают действие пользовательского интерфейса от пользователя или если они содержат сведения, необходимые пользователям специальных возможностей, представляющих интерактивный или значимый пользовательский интерфейс приложения. Не все визуальные элементы UWP имеют одноранговые элементы автоматизации. Примерами классов, реализующих одноранговые элементы автоматизации, являются Button и TextBox. Примерами классов, не реализующих одноранговые элементы автоматизации, являются Border и классы, основанные на Panel, например Grid и Canvas. Panel не имеет однорангового элемента, поскольку обеспечивает только визуальные реакции макета. Для пользователя нет связанного со специальными возможностями способа взаимодействия с Panel. Вместо этого любые дочерние элементы Panel передаются в деревья автоматизации пользовательского интерфейса как дочерние элементы следующего доступного родителя в дереве, имеющего одноранговый элемент или представление элемента.

Ограничения процесса модели автоматизации пользовательского интерфейса и платформы UWP

Обычно код клиента автоматизации пользовательского интерфейса, который получает доступ к приложению UWP, запускается вне процесса. Инфраструктура автоматизации пользовательского интерфейса обеспечивает информацию для выхода за границу процесса. Более подробные сведения об этой концепции см. в разделе Основы модели автоматизации пользовательского интерфейса.

OnCreateAutomationPeer

Все классы, производные от UIElement, содержат защищенный виртуальный метод OnCreateAutomationPeer. Последовательность инициализации объекта для одноранговых элементов автоматизации вызывает OnCreateAutomationPeer, чтобы получить объект однорангового элемента автоматизации для каждого элемента управления и таким образом построить дерево автоматизации пользовательского интерфейса для выполнения во время использования. Код модели автоматизации пользовательского интерфейса может использовать одноранговый элемент для получения информации о характеристиках и функциях элемента управления и для имитации интерактивного использования с помощью своих шаблонов элементов управления. Пользовательский элемент управления, который поддерживает автоматизацию, должен переопределить OnCreateAutomationPeer и возвратить экземпляр класса, производного от AutomationPeer. Например, если пользовательский элемент управления является производным от класса ButtonBase, то объект, возвращенный OnCreateAutomationPeer, должен быть производным от ButtonBaseAutomationPeer.

Если вы пишете класс пользовательского элемента управления и собираетесь также предоставить новый одноранговый элемент автоматизации, вы должны переопределить метод OnCreateAutomationPeer для пользовательского элемента управления так, чтобы он возвращал новый экземпляр вашего однорангового элемента. Одноранговый класс должен непосредственно или косвенно быть производным от класса AutomationPeer.

Например, следующий код объявляет, что пользовательский элемент управления NumericUpDown должен использовать одноранговый элемент NumericUpDownPeer для целей модели автоматизации пользовательского интерфейса.

using Windows.UI.Xaml.Automation.Peers;
...
public class NumericUpDown : RangeBase {
    public NumericUpDown() {
    // other initialization; DefaultStyleKey etc.
    }
    ...
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new NumericUpDownAutomationPeer(this);
    }
}
Public Class NumericUpDown
    Inherits RangeBase
    ' other initialization; DefaultStyleKey etc.
       Public Sub New()
       End Sub
       Protected Overrides Function OnCreateAutomationPeer() As AutomationPeer
              Return New NumericUpDownAutomationPeer(Me)
       End Function
End Class
// NumericUpDown.idl
namespace MyNamespace
{
    runtimeclass NumericUpDown : Windows.UI.Xaml.Controls.Primitives.RangeBase
    {
        NumericUpDown();
        Int32 MyProperty;
    }
}

// NumericUpDown.h
...
struct NumericUpDown : NumericUpDownT<NumericUpDown>
{
	...
    Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer()
    {
        return winrt::make<MyNamespace::implementation::NumericUpDownAutomationPeer>(*this);
    }
};
//.h
public ref class NumericUpDown sealed : Windows::UI::Xaml::Controls::Primitives::RangeBase
{
// other initialization not shown
protected:
    virtual AutomationPeer^ OnCreateAutomationPeer() override
    {
         return ref new NumericUpDownAutomationPeer(this);
    }
};

Примечание

Реализация OnCreateAutomationPeer не должна выполнять никаких других действий, кроме инициализации нового экземпляра пользовательского однорангового элемента автоматизации, передачи вызываемого элемента управления как владельца и возвращения этого экземпляра. Не пытайтесь вводить в этот метод дополнительную логику. В частности, любая логика, которая потенциально способна привести к уничтожению AutomationPeer в рамках того же вызова, может стать причиной непредусмотренного поведения при выполнении.

В типичных реализациях OnCreateAutomationPeerowner указывается как this или Me, потому что переопределение метода находится в той же области, что и остальная часть определения класса элемента управления.

Фактическое определение однорангового класса можно выполнить в файле кода элемента управления или в отдельном файле кода. Все определения одноранговых элементов существуют в пространстве имен Windows.UI.Xaml.Automation.Peers, отдельном от элементов управления, которым они предоставляют одноранговые элементы. Вы можете тоже объявлять свои одноранговые элементы в отдельных пространствах имен, ссылаясь на необходимые пространства имен для вызова метода OnCreateAutomationPeer.

Выбор верного базового класса однорангового элемента

Убедитесь, что ваш класс AutomationPeer является производным от базового класса, который лучше всего подходит для существующей логики одноранговых элементов класса элемента управления, от которого осуществляется наследование. В контексте предыдущего примера, поскольку NumericUpDown происходит от RangeBase, доступен класс RangeBaseAutomationPeer, на основе которого следует создавать одноранговый элемент. Используя самый близкий подходящий одноранговый класс и одновременно отслеживая происхождение самого элемента управления, вы сможете избежать переопределения по крайней мере некоторых функций IRangeValueProvider, потому что базовый одноранговый класс уже реализует их.

В базовом классе Control нет соответствующего однорангового класса. Если требуется одноранговый класс, соответствующий пользовательскому элементу управления, производному от Control, следует наследовать пользовательский одноранговый класс от FrameworkElementAutomationPeer.

В случае наследования непосредственно от ContentControl у класса не будет поведения однорангового элемента автоматизации по умолчанию, так как отсутствует реализация OnCreateAutomationPeer, которая ссылается на одноранговый класс. Поэтому следует реализовать OnCreateAutomationPeer для использования собственного однорангового элемента или использовать FrameworkElementAutomationPeer в качестве однорангового элемента, если такой уровень поддержки специальных возможностей достаточен для вашего элемента управления.

Примечание

В большинстве случаев следует наследовать от AutomationPeer, а не от FrameworkElementAutomationPeer. В случае наследования непосредственно от AutomationPeer вам потребуется дублировать поддержку основных специальных возможностей, которые уже содержатся в FrameworkElementAutomationPeer.

Инициализация пользовательского класса одноранговых элементов

Одноранговый элемент автоматизации должен определять типобезопасный конструктор, который использует экземпляр элемента управления владельца для базовой инициализации. В следующем примере реализация передает значение owner на базу RangeBaseAutomationPeer, и в итоге именно FrameworkElementAutomationPeer фактически использует owner для задания FrameworkElementAutomationPeer.Owner.

public NumericUpDownAutomationPeer(NumericUpDown owner): base(owner)
{}
Public Sub New(owner As NumericUpDown)
    MyBase.New(owner)
End Sub
// NumericUpDownAutomationPeer.idl
import "NumericUpDown.idl";
namespace MyNamespace
{
    runtimeclass NumericUpDownAutomationPeer : Windows.UI.Xaml.Automation.Peers.AutomationPeer
    {
        NumericUpDownAutomationPeer(NumericUpDown owner);
        Int32 MyProperty;
    }
}

// NumericUpDownAutomationPeer.h
...
struct NumericUpDownAutomationPeer : NumericUpDownAutomationPeerT<NumericUpDownAutomationPeer>
{
    ...
    NumericUpDownAutomationPeer(MyNamespace::NumericUpDown const& owner);
};
//.h
public ref class NumericUpDownAutomationPeer sealed :  Windows::UI::Xaml::Automation::Peers::RangeBaseAutomationPeer
//.cpp
public:    NumericUpDownAutomationPeer(NumericUpDown^ owner);

Основные методы AutomationPeer

В связи с особенностями инфраструктуры UWP переопределяемые методы одноранговых элементов автоматизации являются частью пары методов: метода с открытым доступом, который используется поставщиком модели автоматизации пользовательского интерфейса в качестве пункта пересылки для клиентов модели автоматизации пользовательского интерфейса, и защищенного метода настройки Core, который класс UWP может переопределить, чтобы изменить его поведение. Методы в этой паре объединяются по умолчанию так, чтобы при вызове метода доступа всегда вызывался параллельный метод Core, содержащий реализацию поставщика, или так, чтобы резервный метод вызывал реализацию по умолчанию из базовых классов.

При реализации однорангового элемента для пользовательского элемента управления следует переопределить любой из методов Core базового однорангового класса автоматизации в тех случаях, когда от вашего пользовательского элемента управления требуется уникальное поведение. Код автоматизации пользовательского интерфейса получает информацию о вашем элементе управления путем вызова открытых методов однорангового класса. Чтобы предоставить сведения о вашем элементе управления, переопределите каждый метод с именем, оканчивающимся на «Core», когда реализация и дизайн вашего элемента управления создает сценарии специальных возможностей или другие сценарии модели автоматизации пользовательского интерфейса, отличные от поддерживаемых базовым одноранговым классом автоматизации.

Как минимум, при каждом определении нового однорангового класса следует реализовать метод GetClassNameCore, как показано в следующем примере.

protected override string GetClassNameCore()
{
    return "NumericUpDown";
}

Примечание

Вам может понадобиться сохранить строки в виде констант, а не непосредственно в теле метода — вы вольны выбирать. Для GetClassNameCore локализовывать эту строку не нужно. Всякий раз, когда локализованная строка требуется клиенту модели автоматизации пользовательского интерфейса, используется свойство LocalizedControlType, а не ClassName.

GetAutomationControlType

Некоторые специальные возможности непосредственно указывают значение GetAutomationControlType при передаче характеристик элементов в дерево автоматизации пользовательского интерфейса как дополнительную информацию помимо параметра Name модели автоматизации пользовательского интерфейса. Если ваш элемент управления значительно отличается от наследуемого элемента управления и вы хотите сообщить, что его тип отличается от упомянутого в используемом этим элементом управления базовом одноранговом классе, необходимо реализовать одноранговый элемент, а затем переопределить GetAutomationControlTypeCore в вашей реализации однорангового элемента. Это особенно важно, если элемент управления наследует от обобщенного базового класса, например, ItemsControl или ContentControl, в котором базовый одноранговый элемент не сообщает точной информации о типе элемента управления.

Реализация GetAutomationControlTypeCore описывает элемент управления, возвращая значение AutomationControlType. Несмотря на то что вы можете вернуть AutomationControlType.Custom, необходимо возвращать один из более конкретных типов элементов управления, если он точно описывает основные сценарии вашего элемента управления. Пример приведен ниже.

protected override AutomationControlType GetAutomationControlTypeCore()
{
    return AutomationControlType.Spinner;
}

Примечание

Если только вы не задали AutomationControlType.Custom, вам не требуется реализовывать GetLocalizedControlTypeCore для предоставления клиентам значения свойства LocalizedControlType. Общая инфраструктура модели автоматизации пользовательского интерфейса обеспечивает переведенные строки для всех возможных значений AutomationControlType, кроме AutomationControlType.Custom.

GetPattern и GetPatternCore

Реализация однорангового элемента GetPatternCore возвращает объект, который поддерживает шаблон, запрашиваемый в качестве входного параметра. В частности, клиент модели автоматизации пользовательского интерфейса вызывает метод, который передается методу GetPattern поставщика и задает значение перечисления PatternInterface, которое присваивает имя запрошенному шаблону. Переопределение GetPatternCore должно возвращать объект, который реализует указанный шаблон. Этот объект сам представляет собой одноранговый элемент, поскольку одноранговый элемент должен реализовывать соответствующий интерфейс шаблона всякий раз, когда сообщает, что шаблон поддерживается. Если у вашего однорангового элемента нет пользовательской реализации шаблона, но вы знаете, что базовый одноранговый элемент реализует шаблон, вы можете вызвать реализацию базового типа GetPatternCore из своего GetPatternCore. GetPatternCore однорангового элемента должен возвращать значение null, если одноранговый элемент не поддерживает шаблон. Однако, вместо того чтобы возвращать null непосредственно из реализации, обычно осуществляется вызов базовой реализации для возвращения null в случае любого неподдерживаемого шаблона.

Если шаблон поддерживается, реализация GetPatternCore может возвращать this или Me. Ожидается, что клиент модели автоматизации пользовательского интерфейса должен приводить возвращаемое значение GetPattern к интерфейсу запрошенного шаблона каждый раз, когда его значение отличается от null.

Если одноранговый класс наследует от другого однорангового элемента и вся необходимая поддержка и передача сведений о шаблонах уже обрабатывается базовым классом, то в реализации GetPatternCore нет необходимости. Например, если вы реализуете элемент управления диапазоном, который является производным от RangeBase, а ваш одноранговый элемент является производным от RangeBaseAutomationPeer, то этот одноранговый элемент возвращает сам себя для PatternInterface.RangeValue и имеет рабочие реализации интерфейса IRangeValueProvider, который поддерживает шаблон.

Хотя это не буквенный код, данный пример приближается к реализации GetPatternCore, уже присутствующей в RangeBaseAutomationPeer.

protected override object GetPatternCore(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.RangeValue)
    {
        return this;
    }
    return base.GetPattern(patternInterface);
}

Если вы реализуете одноранговый элемент при отсутствии всей необходимой поддержки в базовом одноранговом классе либо вы хотите изменить или добавить элемент в набор шаблонов, унаследованных от базового класса, которые могут поддерживаться вашим одноранговым элементом, то следует переопределить GetPatternCore, чтобы разрешить клиентам модели автоматизации пользовательского интерфейса использовать шаблоны.

Список шаблонов поставщика, которые доступны в UWP-реализации поддержки модели автоматизации пользовательского интерфейса см. в разделе Windows.UI.Xaml.Automation.Provider. Каждый такой шаблон имеет соответствующее значение перечисления PatternInterface; таким способом клиенты модели автоматизации пользовательского интерфейса запрашивают шаблон в вызове GetPattern.

Одноранговый элемент может сообщить, что он поддерживает более одного шаблона. В этом случае переопределение должно включать логику обратного пути для каждого поддерживаемого значения PatternInterface и возвращать одноранговый элемент в каждом соответствующем случае. Ожидается, что вызывающий объект единовременно запрашивает только один интерфейс и сам определяет, следует ли осуществлять приведение к ожидаемому интерфейсу.

Вот пример переопределения GetPatternCore для настраиваемого однорангового элемента. Сообщается о поддержке двух шаблонов — IRangeValueProvider и IToggleProvider. Элементом управления здесь выступает элемент управления отображением мультимедиа, которое может отображаться в полноэкранном режиме (режим переключения) и имеет индикатор выполнения, в пределах которого пользователи могут выбирать положение (элемент управления диапазоном). Этот код взят из примера реализации специальных возможностей на языке XAML.

protected override object GetPatternCore(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.RangeValue)
    {
        return this;
    }
    else if (patternInterface == PatternInterface.Toggle)
    {
        return this;
    }
    return null;
}

Пересылка шаблонов из подэлементов

Реализация метода GetPatternCore может также указывать подэлемент или часть в качестве поставщика шаблона для своего основного элемента. В этом примере имитируется передача элементом ItemsControl обработки шаблона прокрутки одноранговому элементу внутреннего элемента управления ScrollViewer. Чтобы указать подэлемент для обработки шаблона, этот код получает объект подэлемента, создает для подэлемента одноранговый элемент с помощью метода FrameworkElementAutomationPeer.CreatePeerForElement и возвращает новый одноранговый элемент.

protected override object GetPatternCore(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.Scroll)
    {
        ItemsControl owner = (ItemsControl) base.Owner;
        UIElement itemsHost = owner.ItemsHost;
        ScrollViewer element = null;
        while (itemsHost != owner)
        {
            itemsHost = VisualTreeHelper.GetParent(itemsHost) as UIElement;
            element = itemsHost as ScrollViewer;
            if (element != null)
            {
                break;
            }
        }
        if (element != null)
        {
            AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(element);
            if ((peer != null) && (peer is IScrollProvider))
            {
                return (IScrollProvider) peer;
            }
        }
    }
    return base.GetPatternCore(patternInterface);
}

Другие методы Core

Элементу управления может потребоваться поддержка эквивалентов клавиатуры для основных сценариев. Подробнее о том, почему это может понадобиться, см. в статье Специальные возможности клавиатуры. Реализация поддержки ключа является обязательной частью кода элемента управления, но не однорангового элемента, так как она является частью логики элемента управления, а класс однорангового элемента должен переопределить методы GetAcceleratorKeyCore и GetAccessKeyCore, чтобы сообщить клиентам модели автоматизации пользовательского интерфейса, какие ключи используются. Представьте, что эти строки, содержащие ключевую информацию, потребуется локализовать и поэтому они должны происходить из ресурсов, а не из жестко заданных строк.

Если вы предоставляете одноранговый элемент для класса, который поддерживает коллекцию, лучше наследовать от функциональных классов и одноранговых классов, которые уже имеют такого рода поддержку коллекции. Если вы не можете это сделать, возможно, потребуется, чтобы одноранговые элементы для элементов управления, которые поддерживают дочерние коллекции, переопределили одноранговый метод GetChildrenCore, относящийся к коллекции, чтобы должным образом передавать данные о родительско-дочерних отношениях в дерево автоматизации пользовательского интерфейса.

Реализуйте методы IsContentElementCore и IsControlElementCore, чтобы указать, содержит ли элемент управления данные или же выполняет интерактивную роль в пользовательском интерфейсе (либо то и другое одновременно). По умолчанию оба метода возвращают значение true. Эти параметры повышают удобство применения специальных возможностей, таких как программы чтения с экрана, которые могут использовать эти методы для фильтрации дерева автоматизации. Если метод GetPatternCore передает обработку шаблона одноранговому подэлементу, то метод IsControlElementCore однорангового подэлемента может возвращать значение false, чтобы скрыть одноранговый подэлемент из дерева автоматизации.

Некоторые элементы управления могут поддерживать сценарии подписи, при которых текстовая часть подписи предоставляет информацию нетекстовой, или элемент управления должен быть в известных отношениях подписи с другим элементом управления в пользовательском интерфейсе. Если можно предоставить полезное поведение на базе класса, вы сможете переопределить GetLabeledByCore, чтобы обеспечить это поведение.

GetBoundingRectangleCore и GetClickablePointCore в основном используются для сценариев автоматической проверки. Если для элемента управления нужна поддержка автоматической проверки, возможно, придется переопределить эти методы. Это может потребоваться для элементов управления с применением диапазонов, для которых нельзя задать всего одну точку, так как в случае применения диапазона эффект от щелчка пользователем точки в пространственной системе координат будет другим. Например, ScrollBar — одноранговый элемент автоматизации по умолчанию — переопределяет GetClickablePointCore чтобы вернуть «нечисловое» значение Point.

GetLiveSettingCore влияет на элемент управления по умолчанию для значения LiveSetting модели автоматизации пользовательского интерфейса. Возможно, вам придется переопределить его, если вы хотите, чтобы ваш элемент управления возвращал значение, отличное от AutomationLiveSetting.Off. Подробнее о том, что представляет собой LiveSetting, см. в разделе AutomationProperties.LiveSetting.

Вы можете переопределить GetOrientationCore, если ваш элемент управления имеет свойство устанавливаемой ориентации, которое можно сопоставить с AutomationOrientation. Это делают классы ScrollBarAutomationPeer и SliderAutomationPeer.

Базовая реализация в FrameworkElementAutomationPeer

Базовая реализация FrameworkElementAutomationPeer обеспечивает некоторые сведения модели автоматизации пользовательского интерфейса, которые можно интерпретировать посредством различных свойств макета и поведения, определенных на уровне платформы.

  • GetBoundingRectangleCore: возвращает структуру Rect на основании известных характеристик макета. Возвращает нулевое значение Rect, если IsOffscreen имеет значение true.
  • GetClickablePointCore: возвращает структуру Point на основании известных характеристик макета, пока BoundingRectangle имеет значение, отличное от 0.
  • GetNameCore: более комплексное поведение, которое сложно описать здесь; см. раздел GetNameCore. Метод, в сущности, делает попытку строкового преобразования любого известного содержимого ContentControl или связанных классов с содержимым. Кроме того, если у LabeledBy есть значение, значение Name этого элемента используется как Name.
  • HasKeyboardFocusCore: оценивается на основании свойств FocusState и IsEnabled владельца. Элементы, не являющиеся элементами управления, всегда возвращают false.
  • IsEnabledCore: оценивается на основании свойства IsEnabled владельца, если это Control. Элементы, не являющиеся элементами управления, всегда возвращают true. Это не значит, что владелец активен в том смысле, что с ним можно взаимодействовать. Это значит, что одноранговый элемент активен несмотря на то, что владелец не имеет свойства IsEnabled.
  • IsKeyboardFocusableCore: возвращает значение true, если владелец — Control; в противном случае возвращает значение false.
  • IsOffscreenCore: Visibility со значением Collapsed в элементе владельца или любом из его родительских элементов приравнивается к значению true для IsOffscreen. Исключение: объект Popup может быть видимым, даже если родительские элементы его владельца скрыты.
  • SetFocusCore: вызывает Focus.
  • GetParent: вызывает FrameworkElement.Parent владельца и ищет подходящий одноранговый элемент. Эта пара не переопределяется с помощью метода Core, поэтому вы не сможете изменить ее поведение.

Примечание

Одноранговые элементы UWP по умолчанию реализуют поведение с помощью внутреннего машинного кода, который реализует UWP (не обязательно с помощью фактического кода UWP). Вы не сможете увидеть код или логику реализации с помощью отражения среды CLR или других приемов. Вы также не сможете увидеть конкретные справочные страницы для переопределений подклассов реакций базовых одноранговых элементов на события. Например, может существовать дополнительное поведение для метода GetNameCore элемента TextBoxAutomationPeer, которое не будет описано на справочной странице AutomationPeer.GetNameCore, а справочная страница для TextBoxAutomationPeer.GetNameCore отсутствует. Нет даже справочной страницы TextBoxAutomationPeer.GetNameCore. Вместо этого изучите справочный раздел по классу ближайшего однорангового элемента и найдите примечания о реализации в разделе «Примечания».

Одноранговые элементы и AutomationProperties

Ваш одноранговый элемент автоматизации должен обеспечить соответствующие значения по умолчанию для информации о специальных возможностях элемента управления. Обратите внимание, что любой код приложения, который использует элемент управления, может переопределить некоторые аспекты этого поведения, включив значения присоединенных свойств AutomationProperties экземпляров элемента управления. Вызывающие объекты могут сделать это либо для элементов управления по умолчанию, либо для пользовательских элементов управления. Например, следующий КОД XAML создает кнопку с двумя настраиваемыми свойствами автоматизации пользовательского интерфейса: <Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>

Подробнее о присоединенных свойствах AutomationProperties см. в статье Основные сведения о специальных возможностях .

Некоторые из методов AutomationPeer существуют на основании общего контракта относительно того, как поставщики модели автоматизации пользовательского интерфейса должны сообщать сведения, но обычно это не реализовано в одноранговых элементах управления. Это объясняется тем, что такие сведения ожидаются в значениях AutomationProperties, применяемых к коду приложения, который использует элементы управления в конкретном пользовательском интерфейсе. Например, большинство приложений определяют между двумя различными элементами управления в пользовательском интерфейсе связь через метку, применяя значение AutomationProperties.LabeledBy. Однако LabeledByCore реализуется в некоторых одноранговых элементах, которые представляют отношения данных или элемента в элементе управления (например, используя часть заголовка, чтобы задать метку для части поля данных), задавая метки элементам по их контейнерам или в аналогичных случаях.

Реализация шаблонов

Рассмотрим, как написать одноранговый элемент для элемента управления, который реализует поведение свертывания и развертывания путем реализации соответствующего интерфейса шаблона элемента управления. Одноранговый элемент должен разрешать специальные возможности для поведения свертывания и развертывания, возвращая самого себя всякий раз, когда вызывается GetPattern со значением PatternInterface.ExpandCollapse. Одноранговый элемент должен также наследовать интерфейс поставщика для этого шаблона (IExpandCollapseProvider) и предоставлять реализации для каждого из элементов этого интерфейса поставщика. В этом случае интерфейс имеет три элемента для переопределения: Expand, Collapse, ExpandCollapseState.

Полезно заранее планировать специальные возможности в дизайне API самого класса. Всякий раз, когда имеется поведение, которое потенциально запрашивается либо в результате обычного взаимодействия с пользователем, работающим с пользовательским интерфейсом, либо с помощью шаблона поставщика автоматизации, следует предоставлять один метод, который может быть вызван реакцией пользовательского интерфейса или шаблоном автоматизации. Например, если в элементе управления есть кнопочные части с жестко заданными обработчиками событий, которые могут развернуть или свернуть элемент управления, а также клавиатурные эквиваленты для этих действий, сделайте так, чтобы эти обработчики событий вызывали тот же метод, который вы вызываете из тела реализаций Expand или Collapse для IExpandCollapseProvider в одноранговом узле. Использование метода общей логики также может быть действенным способом для того, чтобы убедиться, что визуальные состояния элемента управления обновляются для отображения логических состояний единым образом, независимо от того, как было вызвано поведение.

Типичная реализация подразумевает, что API поставщика сначала вызывают Owner для получения доступа к экземпляру элемента управления во время выполнения. Затем на этом объекте можно вызывать необходимый метод поведения.

public class IndexCardAutomationPeer : FrameworkElementAutomationPeer, IExpandCollapseProvider {
    private IndexCard ownerIndexCard;
    public IndexCardAutomationPeer(IndexCard owner) : base(owner)
    {
         ownerIndexCard = owner;
    }
}

Другой способ реализации заключается в том, что элемент управления сам может ссылаться на свой одноранговый элемент. Этот шаблон обычно употребляется, если события автоматизации создаются из элемента управления, потому что метод RaiseAutomationEvent является методом однорангового элемента.

События модели автоматизации пользовательского интерфейса

События модели автоматизации пользовательского интерфейса делятся на следующие категории.

Событие Описание
Изменение свойства Возникает при изменении свойства элемента автоматизации пользовательского интерфейса или шаблона элемента управления. Например, если клиенту нужно отследить флажок приложения, он может зарегистрироваться на прослушивание изменения свойства в свойстве ToggleState. Когда пользователь устанавливает или снимает флажок, поставщик запускает событие, и клиент может предпринять необходимые действия.
Действие элемента Возникает при изменении результатов пользовательского интерфейса в результате действий пользователя или программы, например при щелчке или вызове кнопки посредством шаблона Invoke.
Изменение структуры Возникает при изменении структуры дерева автоматизации пользовательского интерфейса. Структура меняется, когда новые элементы пользовательского интерфейса отображаются, скрываются или удаляются с рабочего стола.
Глобальное изменение Возникает при осуществлении действий, представляющих особый интерес для клиента, например при переносе фокуса с одного элемента на другой или при закрытии дочернего окна. Некоторые события необязательно означают, что состояние пользовательского интерфейса изменилось. Например, если пользователь переходит к полю ввода текста, а затем нажимает кнопку, чтобы обновить поле, возникает событие TextChanged, даже если пользователь фактически не изменил текст. При обработке события клиентскому приложению может потребоваться проверить, действительно ли что-либо изменилось, перед выполнением действия.

Идентификаторы AutomationEvents

События модели автоматизации пользовательского интерфейса идентифицируются значениями AutomationEvents. Значения перечисления обеспечивают уникальную идентификацию видов событий.

Инициирование событий

Клиенты автоматизации пользовательского интерфейса могут подписываться на события автоматизации. В модели одноранговых элементов автоматизации для пользовательских элементов управления должны сообщаться изменения в состоянии элемента управления, которые имеют отношение к специальным возможностям путем вызова метода RaiseAutomationEvent. Аналогично, при изменении ключевого значения свойства модели автоматизации пользовательского интерфейса одноранговые элементы пользовательского элемента управления должны вызывать метод RaisePropertyChangedEvent.

Следующий образец кода показывает, как получить одноранговый объект из кода определения элемента управления и вызвать метод для создания события из этого однорангового элемента. В качестве оптимизации код определяет, есть ли какие-либо прослушиватели для данного типа события. Инициация события и создание объекта однорангового элемента только при наличии прослушивателей позволяет избежать лишних действий и обеспечивает готовность элемента управления к отклику.

if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
    NumericUpDownAutomationPeer peer =
        FrameworkElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
    if (peer != null)
    {
        peer.RaisePropertyChangedEvent(
            RangeValuePatternIdentifiers.ValueProperty,
            (double)oldValue,
            (double)newValue);
    }
}

Навигация по одноранговым элементам

После обнаружения однорангового элемента автоматизации клиент модели автоматизации пользовательского интерфейса может перемещаться по структуре одноранговых элементов приложения путем вызова методов GetChildren и GetParent однорангового объекта. Навигация между элементами пользовательского интерфейса в элементе управления поддерживается реализацией одноранговых элементов в методе GetChildrenCore. Система модели автоматизации пользовательского интерфейса вызывает этот метод для создания дерева подэлементов, содержащихся в элементе управления; например, элементов списка в поле со списком. Метод по умолчанию GetChildrenCore в FrameworkElementAutomationPeer обходит визуальное дерево элементов для создания дерева одноранговых элементов автоматизации. Пользовательские элементы управления могут переопределять этот метод, чтобы предоставлять другое представление дочерних элементов клиентам автоматизации, возвращая одноранговые элементы автоматизации, которые передают информацию или разрешают взаимодействие с пользователем.

Встроенная поддержка автоматизации для текстовых шаблонов

Некоторые из стандартных одноранговых элементов автоматизации для приложений UWP предоставляют поддержку шаблонов элементов управления для текстовых шаблонов (PatternInterface.Text). Но они предоставляют эту поддержку посредством собственных методов, и затронутые одноранговые элементы не заметят интерфейс ITextProvider в (управляемом) наследовании. Однако если управляемый или неуправляемый клиент модели автоматизации пользовательского интерфейса запрашивает у однорангового элемента шаблоны, он сообщит о поддержке текстового шаблона и предоставит поведение для частей шаблона, когда будут вызваны клиентские API.

Если вы намерены использовать наследование от одного из текстовых элементов управления приложения UWP, а также создать собственный одноранговый элемент, наследующий от одного из связанных с текстом одноранговых элементов, загляните в разделы примечаний для однорангового элемента, чтобы получить дополнительные данные о встроенной поддержке шаблонов. Доступ к встроенному базовому поведению в своем одноранговом элементе можно получить, вызвав базовую реализацию из своих управляемых реализаций интерфейса поставщика, но действия базовой реализации сложно изменить, поскольку собственные интерфейсы как однорангового элемента, так и элемента управления владельца не предоставляются. В целом следует либо использовать базовую реализацию "как есть" (только для вызова базового элемента), либо полностью заменить функциональность на собственный управляемый код и не вызывать базовую реализацию. Последний случай относится к расширенным сценариям, и вам потребуется уверенное владение платформой текстовых служб, которая используется вашим элементом управления, чтобы выполнить требования поддержки специальных возможностей при работе с этой платформой.

Свойство AutomationProperties.AccessibilityView

Помимо предоставления пользовательского однорангового класса вы можете настроить представление в виде дерева для любых экземпляров элемента управления, задав свойство AutomationProperties.AccessibilityView в XAML. Это свойство не реализовано как часть однорангового класса, но мы приводим его здесь, так как оно связано с общей поддержкой специальных возможностей для пользовательских элементов управления или для настраиваемых вами шаблонов.

Основной сценарий использования AutomationProperties.AccessibilityView заключается в намеренном пропуске определенных элементов управления в шаблоне из представлений модели автоматизации пользовательского интерфейса, так как они незначительно влияют на представление специальных возможностей элемента управления в целом. Для предотвращения этого установите для свойства AutomationProperties.AccessibilityView значение "Raw".

Создание исключений в одноранговых элементах автоматизации

API-интерфейсы, реализуемые для поддержки одноранговых элементов автоматизации, могут создавать исключения. Ожидается, что все клиенты автоматизации пользовательского интерфейса, которые прослушивают исключения, достаточно устойчивы, чтобы после большинства создаваемых исключений продолжить работу. Скорее всего, такой прослушиватель просматривает полное дерево автоматизации, включающее не только ваши приложения. Недопустимо, чтобы весь клиент становился недоступным, если в какой-то области дерева возникает исключение однорангового элемента при вызове клиентом своих API.

Для параметров, передаваемых в ваш одноранговый элемент, допустимо проверять входные данные и, например, создавать исключение ArgumentNullException, если передано значение null, которое считается недопустимым для реализации. Однако если одноранговый элемент выполняет дальнейшие операции, то учитывайте, что взаимодействие однорангового элемента с элементом управления, в котором он размещается, носит асинхронный характер. Действия, выполняемые одноранговым элементом, не обязательно блокируют поток пользовательского интерфейса в элементе управления (и, скорее всего, не должны его блокировать). Поэтому возможны ситуации, в которых объект был доступен или имел определенные свойства в момент создания однорангового элемента или в момент первого вызова метода однорангового элемента автоматизации, но затем состояние элемента управления изменилось. В таких случаях поставщик может создавать два специальных исключения.

  • Если не удается получить доступ к владельцу однорангового элемента или к связанному одноранговому элементу по исходным данным, переданным API, создайте исключение ElementNotAvailableException. Например, одноранговый элемент может пытаться выполнять свои методы, но его владелец уже удален из пользовательского интерфейса (например, закрыто модальное диалоговое окно). Для клиента non-.NET это сопоставляется с UIA_E_ELEMENTNOTAVAILABLE.
  • Если владелец еще присутствует, но находится в режиме (например, IsEnabled=false), блокирующем некоторые программные изменения, которые пытается выполнить одноранговый элемент, создайте исключение ElementNotEnabledException. Для клиента non-.NET это сопоставляется с UIA_E_ELEMENTNOTENABLED.

В прочих отношениях в одноранговых элементах следует соблюдать относительно традиционный подход к созданию исключений из поддерживаемых одноранговых элементов. Большинство клиентов не смогут обрабатывать исключения от одноранговых элементов и будут предоставлять пользователю возможность выбора действия при взаимодействии с клиентом. Поэтому иногда разумнее не создавать исключения каждый раз, когда не удается выполнить какое-либо действие в одноранговом элементе, а выполнять операцию и перехватывать исключения без повторного создания в реализации однорангового элемента. Также учитывайте, что большинство клиентов модели автоматизации пользовательского интерфейса написаны в неуправляемом коде. Большинство из них написаны на com и просто проверяют наличие S_OK в HRESULT всякий раз, когда они вызывают метод клиента автоматизации пользовательского интерфейса, который в конечном итоге обращается к вашему однорангового узла.