Implementação do provedor de automação de interface do usuário no lado do servidor

Observação

Esta documentação destina-se a desenvolvedores de .NET Framework que querem usar as classes da Automação da Interface do Usuário gerenciadas definidas no namespace System.Windows.Automation. Para obter as informações mais recentes sobre a Automação da Interface do Usuário, confira API de Automação do Windows: Automação da Interface do Usuário.

Esta seção descreve como implementar um provedor de Automação da interface do usuário do lado do servidor para um controle personalizado.

A implementação de elementos de WPF (Windows Presentation Foundation) e não WPF (como aqueles projetados para Windows Forms) é fundamentalmente diferente. Os elementos do WPF fornecem suporte à Automação da interface do usuário por meio de uma classe derivada de AutomationPeer. Elementos não WPF dão suporte por meio de implementações de interfaces de provedor.

Considerações de segurança

Os provedores devem ser escritos para que possam trabalhar em um ambiente de confiança parcial. Como UIAutomationClient.dll não está configurado para ser executado sob confiança parcial, o código do provedor não deve referenciar esse assembly. Se fizer isso, o código poderá ser executado em um ambiente de confiança total, mas falhará em um ambiente de confiança parcial.

Especificamente, não use campos de classes em UIAutomationClient.dll como aqueles em AutomationElement. Em vez disso, use os campos equivalentes de classes em UIAutomationTypes.dll, como AutomationElementIdentifiers.

Implementação do provedor por elementos do Windows Presentation Foundation

Para saber mais sobre esse tópico, confira Automação da interface do usuário de um controle personalizado do WPF.

Implementação do provedor por elementos não WPF

Controles personalizados que não fazem parte da estrutura do WPF, mas que são escritos em código gerenciado (na maioria das vezes, controles Windows Forms), fornecem suporte para Automação da interface do usuário por meio da implementação de interfaces. Cada elemento deve implementar pelo menos uma das interfaces listadas na primeira tabela na próxima seção. Além disso, se o elemento der suporte a um ou mais padrões de controle, deverá implementar a interface apropriada para cada padrão de controle.

Seu projeto de provedor de automação da interface do usuário deve fazer referência aos seguintes assemblies:

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

Interfaces do provedor

Cada provedor de Automação da interface do usuário deve implementar uma das interfaces a seguir.

Interface Descrição
IRawElementProviderSimple Fornece funcionalidade para um controle simples hospedado em uma janela, incluindo suporte para padrões de controle e propriedades.
IRawElementProviderFragment Herdada de IRawElementProviderSimple. Adiciona funcionalidade para um elemento em um controle complexo, incluindo navegação dentro do fragmento, definição de foco e retorno do retângulo delimitador do elemento.
IRawElementProviderFragmentRoot Herdada de IRawElementProviderFragment. Adiciona funcionalidade ao elemento raiz em um controle complexo, incluindo a localização de um elemento filho em coordenadas especificadas e a definição do estado de foco para todo o controle.

As interfaces a seguir fornecem mais funcionalidade, mas não precisam ser implementadas.

Interface Descrição
IRawElementProviderAdviseEvents Permite que o provedor acompanhe as solicitações de eventos.
IRawElementProviderHwndOverride Permite o reposicionamento de elementos baseados em janelas dentro da árvore de Automação da interface do usuário de um fragmento.

Todas as outras interfaces no namespace System.Windows.Automation.Provider são para suporte ao padrão de controle.

Requisitos para provedores não WPF

Para se comunicar com Automação da interface do usuário, seu controle deve implementar as seguintes áreas principais de funcionalidade:

Funcionalidade Implementação
Expor o provedor à Automação da interface do usuário Em resposta a uma mensagem WM_GETOBJECT enviada à janela de controle, retorna o objeto que implementa IRawElementProviderSimple (ou uma interface derivada). Para fragmentos, esse deve ser o provedor da raiz do fragmento.
Fornecer valores de propriedade Implemente GetPropertyValue para fornecer ou substituir valores.
Permitir que o cliente interaja com o controle Implementar interfaces que dão suporte a padrões de controle, como IInvokeProvider. Retorne esses provedores de padrão em sua implementação de GetPatternProvider.
Acionar eventos Chame um dos métodos estáticos de AutomationInteropProvider acionar um evento que um cliente possa escutar.
Habilitar navegação e foco em um fragmento Implemente IRawElementProviderFragment para cada elemento dentro do fragmento. (Não é necessário para elementos que não fazem parte de um fragmento.)
Habilitar o foco e a localização do elemento filho em um fragmento Implementar IRawElementProviderFragmentRoot. (Não é necessário para elementos que não são raízes de fragmento.)

Valores de propriedade em provedores não WPF

Os provedores de Automação da interface do usuário para controles personalizados devem dar suporte a determinadas propriedades que podem ser usadas pelo sistema de automação, bem como por aplicativos cliente. Para elementos hospedados em janelas (HWNDs), a Automação da interface do usuário pode recuperar algumas propriedades do provedor de janela padrão, mas deve obter outras do provedor personalizado.

Normalmente, os provedores de controles baseados em HWND não precisam fornecer as seguintes propriedades (identificadas por valores de campo):

Observação

O RuntimeIdProperty de um elemento simples ou raiz de fragmento hospedado em uma janela é obtido da janela; no entanto, elementos de fragmento abaixo da raiz (como itens de lista em uma caixa de listagem) devem fornecer seus próprios identificadores. Para obter mais informações, consulte GetRuntimeId.

IsKeyboardFocusableProperty deve ser retornado para provedores hospedados em um controle do Windows Forms. Nesse caso, talvez o provedor de janela padrão não seja capaz de recuperar o valor correto.

Geralmente, NameProperty, é fornecido pelo provedor do host. Por exemplo, se um controle personalizado for derivado de Control, o nome será derivado da propriedade Text do controle.

Por ver um exemplo de código, confira Propriedades de retorno de um provedor de Automação da interface do usuário.

Eventos em provedores não WPF

Provedores de Automação da interface do usuário devem gerar eventos para notificar os aplicativos cliente de alterações no estado da interface do usuário. Os métodos a seguir são usados para gerar eventos.

Método Descrição
RaiseAutomationEvent Gera vários eventos, incluindo eventos disparados por padrões de controle.
RaiseAutomationPropertyChangedEvent Gera um evento quando uma propriedade de Automação da interface do usuário tiver sido alterada.
RaiseStructureChangedEvent Gera um evento quando a estrutura da árvore de Automação da interface do usuário tiver sido alterada; por exemplo, pela remoção ou adição de um elemento.

A finalidade de um evento é notificar o cliente de algo que está ocorrendo na interface do usuário (IU), se a atividade é disparada ou não pelo próprio sistema Automação da interface do usuário. Por exemplo, o evento identificado por InvokedEvent deve ser gerado sempre que o controle é invocado, seja por meio da entrada direta do usuário ou da chamada de Invoke por parte do aplicativo cliente.

Para otimizar o desempenho, um provedor pode gerar eventos seletivamente ou não gerar eventos se nenhum aplicativo cliente estiver registrado para recebê-los. Os métodos a seguir são usados para otimização.

Método Descrição
ClientsAreListening Essa propriedade estática especifica se os aplicativos cliente se inscreveram em eventos de Automação da interface do usuário.
IRawElementProviderAdviseEvents A implementação dessa interface por parte do provedor em uma raiz de fragmento permite que ela seja aconselhada quando os clientes registrarem e cancelarem o registro de manipuladores de eventos para eventos no fragmento.

Navegação de provedor não WPF

Os provedores de controles simples, como um botão personalizado hospedado em uma janela (HWND), não precisam dar suporte à navegação na árvore de Automação da interface do usuário. A navegação de e para o elemento é tratada pelo provedor padrão para a janela do host, que é especificada na implementação de HostRawElementProvider. No entanto, quando você implementa um provedor para um controle personalizado complexo, deve dar suporte à navegação entre o nó raiz do fragmento e seus descendentes e entre nós irmãos.

Observação

Elementos de um fragmento diferente da raiz devem retornar uma referência null de HostRawElementProvider, pois não estão hospedados diretamente em uma janela e nenhum provedor padrão pode dar suporte à navegação entre eles.

A estrutura do fragmento é determinada pela implementação de Navigate. Para cada direção possível de cada fragmento, esse método retorna o objeto de provedor para o elemento nessa direção. Se não houver nenhum elemento nessa direção, o método retornará uma referência null.

A raiz do fragmento dá suporte à navegação somente para elementos filho. Por exemplo, uma caixa de listagem retorna o primeiro item na lista quando a direção é FirstChild, e o último item quando a direção é LastChild. A raiz do fragmento não dá suporte à navegação para um pai ou irmãos; isso é tratado pelo provedor da janela do host.

Elementos de um fragmento que não são a raiz devem dar suporte à navegação ao pai e a todos os irmãos e filhos que eles têm.

Reassociação de provedor não WPF

As janelas pop-up são, na verdade, janelas de nível superior e, por padrão, aparecem na árvore de Automação da interface do usuário como filhos da área de trabalho. Em muitos casos, no entanto, janelas pop-up são logicamente filhas de algum outro controle. Por exemplo, a lista suspensa de uma caixa de combinação é logicamente um filho da caixa de combinação. Da mesma forma, uma janela pop-up de menu é logicamente um filho do menu. A Automação da interface do usuário dá suporte a janelas pop-up reassociadas para que pareçam ser filhos do controle associado.

Para reassociar uma janela pop-up:

  1. Crie um provedor para a janela pop-up. Isso exige que a classe da janela pop-up seja conhecida com antecedência.

  2. Implemente todas as propriedades e padrões como de costume para esse pop-up, como se fosse um controle por si só.

  3. Implemente a propriedade HostRawElementProvider para que ela retorne o valor obtido de HostProviderFromHandle, em que o parâmetro é o identificador de janela da janela pop-up.

  4. Implemente Navigate para a janela pop-up e seu pai para que a navegação seja tratada corretamente do pai lógico para os filhos lógicos e entre filhos irmãos.

Quando a Automação da interface do usuário encontra a janela pop-up, ela reconhece que a navegação está sendo substituída do padrão e ignora a janela pop-up quando ela é encontrada como um filho da área de trabalho. Em vez disso, o nó só será acessível por meio do fragmento.

A reassociação não é adequada para casos em que um controle pode hospedar uma janela de qualquer classe. Por exemplo, um controle rebar pode hospedar qualquer tipo de HWND em suas faixas. Para lidar com esses casos, a Automação da interface do usuário dá suporte a uma forma alternativa de realocação de HWND, conforme descrito na próxima seção.

Reposicionamento de provedor não WPF

Os fragmentos da Automação da interface do usuário podem conter dois ou mais elementos contidos em uma janela (HWND). Como cada HWND tem seu próprio provedor padrão que considera o HWND um filho de um HWND independente, a árvore Automação da interface do usuário mostrará, por padrão, os HWNDs no fragmento como filhos da janela pai. Na maioria dos casos, esse é um comportamento desejável, mas às vezes pode causar confusão porque não corresponde à estrutura lógica da interface do usuário.

Um bom exemplo disso é um controle rebar. Uma rebar contém faixas, cada uma das quais, por sua vez, pode conter um controle baseado em HWND, como uma barra de ferramentas, uma caixa de edição ou uma caixa de combinação. O provedor de janela padrão para a HWND de rebar vê os HWNDs de controle de faixa como filhos, e o provedor de rebar vê as faixas como filhos. Como o provedor HWND e o provedor de rebar estão trabalhando em conjunto e combinando seus filhos, as faixas e os controles baseados em HWND aparecem como filhos do rebar. Logicamente, no entanto, apenas as bandas devem aparecer como filhos do rebar e cada provedor de faixa deve ser acoplado ao provedor HWND padrão para o controle que ele contém.

Para fazer isso, o provedor raiz de fragmento do rebar expõe um conjunto de filhos que representam as faixas. Cada faixa tem um único provedor que pode expor propriedades e padrões. Em sua implementação de HostRawElementProvider, a faixa retorna o provedor de janela padrão para o HWND de controle, que ele obtém chamando HostProviderFromHandle, passando o identificador de janela do controle. Por fim, o provedor raiz de fragmento do rebar implementa a interface IRawElementProviderHwndOverride e, em sua implementação de GetOverrideProviderForHwnd retorna o provedor de faixa apropriado para o controle contido no HWND especificado.

Confira também