Implementación del proveedor de UI Automation en el servidor

Nota

Esta documentación está dirigida a los desarrolladores de .NET Framework que quieran usar las clases de automatización de la interfaz de usuario administradas definidas en el espacio de nombres System.Windows.Automation. Para ver la información más reciente acerca de la automatización de la interfaz de usuario, consulte Windows Automation API: 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 Windows Presentation Foundation (WPF) y elementos que no son de WPF (como los diseñados para Windows Forms) es fundamentalmente diferente. Los elementos WPF son compatibles con Automatización de la interfaz de usuario mediante una clase derivada de AutomationPeer. Los elementos que no son de WPF lo consiguen a través de implementaciones de interfaces de proveedor.

Consideraciones sobre la seguridad

Los proveedores deben escribirse para 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. En caso contrario, el código podría ejecutarse en un entorno de plena confianza, pero se producirá un error en un entorno de confianza parcial.

De forma específica, no use los campos de las clases de UIAutomationClient.dll, como los de AutomationElement. En su lugar, use los campos equivalentes de las clases de UIAutomationTypes.dll, como AutomationElementIdentifiers.

Implementación del proveedor con los 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 con elementos que no son de WPF

Los controles personalizados que no forman parte del marco de WPF, pero están escritos en el código administrado (en la mayoría de las ocasiones se trata de controles de Windows Forms), son compatibles con Automatización de la interfaz de usuario gracias a 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 es compatible con uno o varios patrones de control, debe implementar la interfaz adecuada para cada uno de ellos.

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. Es compatible con las propiedades y los patrones de control.
IRawElementProviderFragment Se hereda de IRawElementProviderSimple. Agrega una funcionalidad para un elemento de un control complejo, incluida la navegación por el fragmento, el establecimiento del foco y la devolución del rectángulo delimitador del elemento.
IRawElementProviderFragmentRoot Se hereda de IRawElementProviderFragment. Agrega funcionalidad para el elemento raíz de un control complejo, incluida la ubicación de un elemento secundario en las coordenadas especificadas y el establecimiento del estado del foco global del control.

Las interfaces siguientes incrementan la funcionalidad, pero no se requiere su implementación.

Interfaz Descripción
IRawElementProviderAdviseEvents Habilita al proveedor para realizar un seguimiento de las solicitudes de eventos.
IRawElementProviderHwndOverride Habilita la reordenación de los elementos basados en ventanas en el árbol de Automatización de la interfaz de usuario de un fragmento.

Todas las demás interfaces del espacio de nombres de System.Windows.Automation.Provider son compatibles con el patrón de control.

Requisitos para los proveedores que no son de WPF

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

Funcionalidad Implementación
Exposición del proveedor a Automatización de la interfaz de usuario En respuesta a un mensaje 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 las raíces correspondientes.
Proporcionar valores de propiedad Implemente GetPropertyValue para proporcionar o reemplazar valores.
Habilitar al cliente para interactuar con el control Implemente interfaces compatibles con los patrones de control, como IInvokeProvider. Devuelva 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 pueda escuchar un cliente.
Habilitar la navegación y el establecimiento del foco en un fragmento Implemente IRawElementProviderFragment para cada elemento del fragmento (no es necesario para los elementos que no forman parte de un fragmento).
Habilitar el establecimiento del foco y la ubicación del elemento secundario de un fragmento Implemente IRawElementProviderFragmentRoot. (no es necesario para los elementos que no son raíces de fragmento).

Valores de propiedad de los proveedores que no son de WPF

En lo que respecta a los controles personalizados, los proveedores de Automatización de la interfaz de usuario deben ofrecer compatibilidad con ciertas propiedades que pueden usar tanto el sistema de automatización como las aplicaciones cliente. Para los elementos que se hospedan en ventanas (HWND), Automatización de la interfaz de usuario puede recuperar algunas propiedades del proveedor de ventana predeterminado, pero debe obtener otras del proveedor personalizado.

Por lo general, en lo que respecta a los controles basados en HWND, los proveedores no necesitan proporcionar las propiedades siguientes (identificadas por los valores de campo):

Nota

El objeto RuntimeIdProperty de un elemento simple o una raíz de fragmento hospedada en una ventana se obtiene de la ventana. No obstante, los elementos del fragmento situados debajo de la raíz (por ejemplo, los elementos de lista de un cuadro de lista) deben proporcionar sus propios identificadores. Para obtener más información, vea GetRuntimeId.

Los proveedores hospedados en un control de Windows Forms deben devolver el elemento IsKeyboardFocusableProperty. En este caso, es posible que el proveedor de ventana predeterminado no consiga recuperar el valor correcto.

Por lo general, el elemento NameProperty lo proporciona el proveedor de host. Por ejemplo, si se deriva un control personalizado de Control, el nombre derivará de la propiedad Text del control.

Para obtener código de ejemplo, vea Return Properties from a UI Automation Provider.

Eventos de 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. Para generar eventos, se usan los métodos siguientes:

Método Descripción
RaiseAutomationEvent Genera varios eventos, incluidos los que desencadenan los patrones de control.
RaiseAutomationPropertyChangedEvent Genera un evento cuando una propiedad de Automatización de la interfaz de usuario ha cambiado.
RaiseStructureChangedEvent Genera un evento cuando la estructura del árbol de Automatización de la interfaz de usuario ha cambiado. Por ejemplo, cuando se agrega o elimina un elemento.

El propósito de un evento es notificar al cliente algo que ha sucedido en la interfaz de usuario, independientemente de si el propio sistema de Automatización de la interfaz de usuario desencadena o no la actividad. Por ejemplo, el evento que identifica InvokedEvent debe generarse siempre que se invoca el control a través de la entrada directa del usuario o cuando la aplicación cliente llama a Invoke.

Para optimizar el rendimiento, un proveedor puede generar eventos de forma selectiva o no generarlos en absoluto si no se registra ninguna aplicación cliente para recibirlos. Para conseguir esta optimización, se usan los métodos siguientes:

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 una raíz de fragmento permite recibir información cuando los clientes registran controladores de eventos o anulan su registro en los eventos del fragmento.

Navegación de proveedores que no son de WPF

Los proveedores de los controles simples, como los botones personalizados hospedados en ventanas (HWND), no deben tienen que ser compatibles necesariamente con la navegación dentro del árbol de Automatización de la interfaz de usuario. La navegación hacia y desde el elemento se controla con el proveedor predeterminado de la ventana host, que se especifica en la implementación de HostRawElementProvider. Sin embargo, cuando se implementa un proveedor para un control personalizado complejo, sí se debe admitir la navegación entre el nodo raíz del fragmento y sus descendientes, y entre los nodos del mismo nivel.

Nota

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

La estructura del fragmento queda determinada por la implementación de Navigate. Este método devuelve el objeto de proveedor para el elemento en cada dirección posible, desde cada fragmento. Si no hay ningún elemento en una dirección determinada, el método devuelve una referencia null .

La raíz de fragmento solo permite navegar hacia los elementos secundarios. Por ejemplo, un cuadro de lista devuelve el primer elemento de la lista cuando la dirección es FirstChild, y el último elemento cuando la dirección es LastChild. La raíz de fragmento no admite la navegación a un elemento primario o del mismo nivel. Esto se controla desde el proveedor de ventana host.

Los elementos de un fragmento que no son la raíz deben admitir la navegación hacia el elemento primario, sus elementos secundarios y los elementos del mismo nivel que estos contengan.

Reorganización dinámica de relación jerárquica de proveedores que no son de WPF

Las ventanas emergentes son en realidad ventanas de nivel superior. Por ello, aparecen de forma predeterminada en el árbol de Automatización de la interfaz de usuario como elementos secundarios del escritorio. No obstante, en muchos casos, las ventanas emergentes son, lógicamente, elementos secundarios de otros controles. Por ejemplo, la lista desplegable de un cuadro combinado es, lógicamente, un elemento secundario de dicho cuadro. De forma similar, una ventana emergente de menú es, lógicamente, un elemento secundario de un menú. Automatización de la interfaz de usuario permite reorganizar de forma dinámica la relación jerárquica de las ventanas emergentes para que parezcan elementos secundarios del control asociado.

Para reorganizar de forma dinámica la relación jerárquica de una ventana emergente:

  1. Cree un proveedor para la ventana emergente. Para ello, se debe conocer por adelantado la clase de la ventana emergente.

  2. Implemente todas las propiedades y los patrones con el proceso habitual para los elementos emergentes, como si se tratase de un control por derecho propio.

  3. Implemente la propiedad HostRawElementProvider 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 elemento primario, de modo que la navegación pueda controlarse correctamente desde el elemento primario lógico hacia los elementos secundarios lógicos, y entre los elementos secundarios del mismo nivel.

Cuando Automatización de la interfaz de usuario encuentra la ventana emergente, reconoce que se está reemplazando la configuración predeterminada de la navegación y omite esta ventana cuando se encuentra como elemento secundario del escritorio. En su lugar, solo podrá accederse al nodo a través del fragmento.

La reorganización dinámica de relación jerárquica no es adecuada cuando un control puede hospedar una ventana de cualquier clase. Por ejemplo, un rebar puede hospedar cualquier tipo de HWND en sus bandas. Para controlar estos casos, Automatización de la interfaz de usuario permite reubicar HWND con un procedimiento alternativo, que se describe en la sección siguiente.

Reordenación de proveedores que no son de WPF

Los fragmentos de Automatización de la interfaz de usuario pueden contener dos o más elementos, contenidos todos ellos en ventanas (HWND). Dado que cada HWND tiene su propio proveedor predeterminado que lo considera como elemento secundario de otro HWND contenedor, el árbol de Automatización de la interfaz de usuario mostrará, de forma predeterminada, los HWND del fragmento como elementos secundarios de la ventana primaria. En la mayoría de los casos este sería el comportamiento deseable, pero a veces puede llevar a confusión porque no coincide con la estructura lógica de la interfaz de usuario.

Un buen ejemplo de esto lo constituye un control rebar. Un rebar contiene bandas, cada una de las cuales puede incluir a su vez un control basado en HWND, como una barra de herramientas, un cuadro de edición o un cuadro combinado. El proveedor de ventana predeterminado del HWND de rebar considera los HWND del control de banda como elementos secundarios, y el proveedor de rebar considera las bandas como elementos secundarios. Dado que los proveedores de HWND y rebar trabajan en tándem y combinan sus elementos secundarios, tanto las bandas como los controles basados en HWND aparecen como elementos secundarios del rebar. Sin embargo, lógicamente, solo deberían aparecer las bandas como elementos secundarios del rebar, y cada proveedor de banda debería acoplarse con el proveedor de HWND predeterminado para el control que contiene.

Para ello, el proveedor de raíz de fragmento del rebar expone un conjunto de elementos secundarios que representan a las bandas. Cada banda tiene un proveedor único que puede exponer propiedades y patrones. En su implementación de HostRawElementProvider, el proveedor de banda devuelve el proveedor de ventana predeterminado para el HWND de control. Para obtenerlo, llama a HostProviderFromHandley pasa el identificador de ventana del control. Por último, el proveedor de raíz de fragmento del rebar implementa la interfaz de IRawElementProviderHwndOverride y, en su implementación de GetOverrideProviderForHwnd , devuelve el proveedor de banda adecuado para el control que contiene el HWND especificado.

Consulte también