Implementación del proveedor de automatización de la interfaz de usuario del lado del servidor

Nota:

Esta documentación está pensada para desarrolladores de .NET Framework que desean usar las clases de automatización de la interfaz de usuario administradas definidas en el espacio de nombres System.Windows.Automation. Para obtener la información más reciente sobre la automatización de la interfaz de usuario, consulte API de Automatización de Windows: Automatización de la interfaz de usuario.

En esta sección se describe cómo implementar un proveedor de automatización de la interfaz de usuario del lado servidor para un control personalizado.

La implementación de elementos de Windows Presentation Foundation (WPF) y elementos que no son WPF (como los diseñados para Windows Forms) es fundamentalmente diferente. Los elementos de WPF proporcionan compatibilidad con la automatización de la interfaz de usuario a través de una clase derivada de AutomationPeer. Los elementos que no son de WPF proporcionan compatibilidad a través de implementaciones de interfaces de proveedor.

Consideraciones de seguridad

Los proveedores deben escribirse para que puedan funcionar en un entorno de confianza parcial. Dado que UIAutomationClient.dll no está configurado para ejecutarse con confianza parcial, el código del proveedor no debe hacer referencia a ese ensamblado. Si lo hace, el código puede ejecutarse en un entorno de plena confianza pero, a continuación, producir un error en un entorno de confianza parcial.

En concreto, no use campos de clases de UIAutomationClient.dll como las de AutomationElement. En su lugar, use los campos equivalentes de las clases de UIAutomationTypes.dll, como AutomationElementIdentifiers.

Implementación del proveedor por elementos de Windows Presentation Foundation

Para obtener más información sobre este tema, consulte Automatización de la interfaz de usuario de un control personalizado de WPF.

Implementación del proveedor por elementos que no son WPF

Los controles personalizados que no forman parte del marco wpF, pero que se escriben en código administrado (con más frecuencia son controles de Windows Forms), proporcionan compatibilidad con la automatización de la interfaz de usuario mediante la implementación de interfaces. Cada elemento debe implementar al menos una de las interfaces enumeradas en la primera tabla de la sección siguiente. Además, si el elemento admite uno o varios patrones de control, debe implementar la interfaz adecuada para cada patrón de control.

El proyecto del proveedor de automatización de la interfaz de usuario debe hacer referencia a los ensamblados siguientes:

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

Interfaces de proveedor

Cada proveedor de automatización de la interfaz de usuario debe implementar una de las interfaces siguientes.

Interfaz Descripción
IRawElementProviderSimple Proporciona funcionalidad para un control simple hospedado en una ventana, incluida la compatibilidad con patrones de control y propiedades.
IRawElementProviderFragment Hereda de IRawElementProviderSimple. Agrega funcionalidad para un elemento de un control complejo, incluida la navegación dentro del fragmento, el establecimiento del foco y la devolución del rectángulo delimitador del elemento.
IRawElementProviderFragmentRoot Hereda de IRawElementProviderFragment. Agrega funcionalidad para el elemento raíz en un control complejo, incluida la ubicación de un elemento secundario en coordenadas especificadas y el establecimiento del estado de foco para todo el control.

Las interfaces siguientes proporcionan funcionalidad agregada, pero no son necesarias para implementarse.

Interfaz Descripción
IRawElementProviderAdviseEvents Permite al proveedor realizar un seguimiento de las solicitudes de eventos.
IRawElementProviderHwndOverride Permite cambiar la posición de los elementos basados en ventanas dentro del árbol de automatización de la interfaz de usuario de un fragmento.

Todas las demás interfaces del System.Windows.Automation.Provider espacio de nombres son compatibles con patrones de control.

Requisitos para proveedores no basados en WPF

Para comunicarse con la automatización de la interfaz de usuario, el control debe implementar las siguientes áreas principales de funcionalidad:

Funcionalidad Implementation
Exposición del proveedor a automatización de la interfaz de usuario En respuesta a un mensaje de WM_GETOBJECT enviado a la ventana de control, devuelva el objeto que implementa IRawElementProviderSimple (o una interfaz derivada). En el caso de los fragmentos, debe ser el proveedor de la raíz del fragmento.
Proporcionar valores de propiedad Implemente GetPropertyValue para proporcionar o invalidar valores.
Permitir que el cliente interactúe con el control Implemente interfaces que admitan patrones de control, como IInvokeProvider. Devuelve estos proveedores de patrones en la implementación de GetPatternProvider.
Generar eventos Llame a uno de los métodos estáticos de AutomationInteropProvider para generar un evento que un cliente pueda escuchar.
Habilitar la navegación y la focalización dentro de un fragmento Implemente IRawElementProviderFragment para cada elemento dentro del fragmento. (No es necesario para los elementos que no forman parte de un fragmento).
Permitir el enfoque y la localización del elemento hijo en un fragmento Implemente IRawElementProviderFragmentRoot. (No es necesario para los elementos que no son raíces del fragmento).

Valores de propiedad en proveedores no pertenecientes a WPF

Los proveedores de automatización de la interfaz de usuario para controles personalizados deben admitir determinadas propiedades que el sistema de automatización puede usar, así como las aplicaciones cliente. En el caso de los elementos hospedados en ventanas (HWND), la automatización de la interfaz de usuario puede recuperar algunas propiedades del proveedor de ventanas predeterminado, pero debe obtener otras del proveedor personalizado.

Los proveedores de controles basados en HWND no suelen necesitar proporcionar las siguientes propiedades (identificadas por valores de campo):

Nota:

El RuntimeIdProperty de un elemento simple o raíz de fragmento hospedado en una ventana se obtiene de la ventana; sin embargo, los elementos de fragmento debajo de la raíz (como los elementos de la lista en un cuadro de lista) deben tener sus propios identificadores. Para obtener más información, consulte GetRuntimeId.

IsKeyboardFocusableProperty Debe devolverse para los proveedores hospedados en un control de Windows Forms. En este caso, es posible que el proveedor de ventanas predeterminado no pueda recuperar el valor correcto.

Normalmente, NameProperty es proporcionado por el proveedor de alojamiento. Por ejemplo, si un control personalizado se deriva de Control, el nombre se deriva de la Text propiedad del control.

Para obtener código de ejemplo, vea Devolver propiedades de un proveedor de automatización de la interfaz de usuario.

Eventos en proveedores que no son de WPF

Los proveedores de automatización de la interfaz de usuario deben generar eventos para notificar a las aplicaciones cliente los cambios en el estado de la interfaz de usuario. Los métodos siguientes se usan para generar eventos.

Método Descripción
RaiseAutomationEvent Genera varios eventos, incluidos los eventos desencadenados por patrones de control.
RaiseAutomationPropertyChangedEvent Genera un evento cuando ha cambiado una propiedad de Automatización de la interfaz de usuario.
RaiseStructureChangedEvent Genera un evento cuando la estructura del árbol de automatización de la interfaz de usuario ha cambiado; por ejemplo, mediante la eliminación o adición de un elemento.

El propósito de un evento es notificar al cliente algo que tiene lugar en la interfaz de usuario (UI), tanto si el sistema de automatización de la interfaz de usuario desencadena o no la actividad. Por ejemplo, el evento identificado por InvokedEvent debe generarse cada vez que se invoca el control, ya sea a través de la entrada directa del usuario o mediante la aplicación cliente que llama a Invoke.

Para optimizar el rendimiento, un proveedor puede generar eventos de forma selectiva o no generar ningún evento si no hay ninguna aplicación cliente registrada para recibirlos. Los métodos siguientes se usan para la optimización.

Método Descripción
ClientsAreListening Esta propiedad estática especifica si alguna aplicación cliente se ha suscrito a eventos de automatización de la interfaz de usuario.
IRawElementProviderAdviseEvents La implementación del proveedor de esta interfaz en la raíz de un fragmento le permite ser notificado cuando los clientes registran y anulan el registro de controladores de eventos en el fragmento.

Navegación del proveedor no WPF

Los proveedores de controles simples, como un botón personalizado hospedado en una ventana (HWND) no necesitan admitir la navegación dentro del árbol de automatización de la interfaz de usuario. El proveedor predeterminado gestiona la navegación hacia y desde el elemento en la ventana de host, que se especifica en la implementación de HostRawElementProvider. Sin embargo, al implementar un proveedor para un control personalizado complejo, debe admitir la navegación entre el nodo raíz del fragmento y sus descendientes y entre nodos del mismo nivel.

Nota:

Los elementos de un fragmento distinto de la raíz deben devolver una null referencia de HostRawElementProvider, ya que no se hospedan directamente en una ventana, y ningún proveedor predeterminado puede admitir la navegación hacia y desde ellos.

La estructura del fragmento viene determinada por la implementación de Navigate. Para cada dirección posible de cada fragmento, este método devuelve el objeto proveedor para el elemento que se encuentra en esa dirección. Si no hay ningún elemento en esa dirección, el método devuelve una null referencia.

La raíz del fragmento solo admite la navegación a elementos secundarios. Por ejemplo, un cuadro de lista devuelve el primer elemento de la lista cuando la dirección es FirstChildy el último elemento cuando la dirección es LastChild. La raíz del fragmento no admite la navegación a un nodo padre o hermanos; el proveedor de la ventana anfitriona se encarga de esto.

Los elementos de un fragmento que no son la raíz deben admitir la navegación al elemento padre, así como a cualquier hermano o hijo que tengan.

Cambio de jerarquía para proveedores que no son WPF

Las ventanas emergentes son en realidad ventanas de nivel superior, por lo que de forma predeterminada aparecen en el árbol de automatización de la interfaz de usuario como elementos secundarios del escritorio. Sin embargo, en muchos casos, las ventanas emergentes son hijos lógicos de algún otro control. Por ejemplo, la lista desplegable de un cuadro combinado es lógicamente un elemento secundario del cuadro combinado. De forma similar, una ventana emergente de menú es lógicamente un elemento secundario del menú. La automatización de la interfaz de usuario ofrece soporte para reasignar la jerarquía de las ventanas emergentes, de modo que parezcan ser elementos subordinados del control asociado.

Para reparentar una ventana emergente:

  1. Cree un proveedor para la ventana emergente. Esto requiere que la clase de la ventana emergente se conozca de antemano.

  2. Implemente todas las propiedades y patrones como de costumbre para esa ventana emergente, como si fuera un control independiente.

  3. Implemente la HostRawElementProvider propiedad para que devuelva el valor obtenido de HostProviderFromHandle, donde el parámetro es el identificador de ventana de la ventana emergente.

  4. Implemente Navigate para la ventana emergente y su padre lógico para que la navegación se controle correctamente desde el padre lógico a los hijos lógicos y entre los hijos del mismo nivel.

Cuando Automatización de la Interfaz de Usuario encuentra la ventana emergente, reconoce que la navegación se está anulando desde el predeterminado, y omite la ventana emergente cuando se encuentra como subelemento del escritorio. En su lugar, el nodo solo será accesible a través del fragmento.

La reparentación no es adecuada para los casos en los que un control puede hospedar una ventana de cualquier clase. Por ejemplo, una barra de herramientas puede alojar cualquier tipo de HWND en sus bandas. Para controlar estos casos, UI Automation admite una forma alternativa de reubicación de HWND, como se describe en la sección siguiente.

Cambio de posición de proveedores que no son WPF

Los fragmentos de automatización de la interfaz de usuario pueden contener dos o más elementos incluidos en una ventana (HWND). Dado que cada HWND tiene su propio proveedor predeterminado que considera que HWND es un elemento secundario de un HWND contenedor, el árbol de automatización de la interfaz de usuario mostrará, de forma predeterminada, los HWND en el fragmento como elementos secundarios de la ventana primaria. En la mayoría de los casos, esto es un comportamiento deseable, pero a veces puede provocar confusión porque no coincide con la estructura lógica de la interfaz de usuario.

Un buen ejemplo de esto es un control de barras de refuerzo. Un rebar contiene bandas, cada una de las cuales puede contener a su vez un control basado en HWND, como una barra de herramientas, un cuadro de texto o un cuadro combinado. El proveedor de ventana predeterminado de la barra de rebar HWND ve los HWND de control de banda como elementos secundarios y el proveedor de la barra de rebar ve las bandas como elementos secundarios. Dado que el proveedor de HWND y el proveedor de rebar están trabajando en conjunto y combinando sus elementos secundarios, tanto las bandas como los controles basados en HWND aparecen como elementos secundarios de la barra de rebar. Lógicamente, solo las bandas deben aparecer como elementos secundarios del rebar, y cada proveedor de banda debe estar acoplado con el proveedor HWND predeterminado para el control que contiene.

Para ello, el proveedor raíz del fragmento de la barra expone un conjunto de hijos que representan las bandas. Cada banda tiene un único proveedor que puede exponer propiedades y patrones. En su implementación de HostRawElementProvider, el proveedor de banda devuelve el proveedor de la ventana predeterminado para el HWND del control, que obtiene llamando a HostProviderFromHandle, pasando el identificador de ventana del control. Por último, el proveedor raíz de fragmento para rebar implementa la interfaz IRawElementProviderHwndOverride, y en su implementación de GetOverrideProviderForHwnd, devuelve el proveedor de banda adecuado para el control contenido en el HWND especificado.

Consulte también