Compartir a través de


Automatización del mismo nivel personalizado

Describe el concepto de automatización del mismo nivel para Microsoft Automatización de la interfaz de usuario y cómo puede proporcionar compatibilidad con la automatización para su propia clase de interfaz de usuario personalizada.

Automatización de la interfaz de usuario proporciona un marco que los clientes de automatización pueden usar para examinar o operar las interfaces de usuario de una variedad de plataformas y marcos de interfaz de usuario. Si está escribiendo una aplicación de Windows, las clases que usa para la interfaz de usuario ya proporcionan compatibilidad con Automatización de la interfaz de usuario. Puede derivar de clases existentes no selladas para definir un nuevo tipo de control de interfaz de usuario o clase de soporte técnico. En el proceso de hacerlo, la clase podría agregar un comportamiento que debería tener compatibilidad con la accesibilidad, pero que la compatibilidad predeterminada Automatización de la interfaz de usuario no cubre. En este caso, debes ampliar la compatibilidad existente Automatización de la interfaz de usuario derivando de la clase AutomationPeer que usó la implementación base, agregando cualquier soporte necesario a la implementación del mismo nivel e informando a la infraestructura de control de aplicaciones de Windows que debería crear el nuevo mismo nivel.

Automatización de la interfaz de usuario permite no solo aplicaciones de accesibilidad ni tecnologías de asistencia, como lectores de pantalla, sino también código de control de calidad (prueba). En cualquier escenario, Automatización de la interfaz de usuario clientes pueden examinar los elementos de la interfaz de usuario y simular la interacción del usuario con la aplicación desde otro código fuera de la aplicación. Para obtener información sobre Automatización de la interfaz de usuario en todas las plataformas y en su significado más amplio, consulte Automatización de la interfaz de usuario Información general.

Hay dos audiencias distintas que usan el marco de Automatización de la interfaz de usuario.

  • Automatización de la interfaz de usuario clientes llaman a Automatización de la interfaz de usuario API para obtener información sobre toda la interfaz de usuario que se muestra actualmente al usuario. Por ejemplo, una tecnología de asistencia, como un lector de pantalla, actúa como un cliente Automatización de la interfaz de usuario. La interfaz de usuario se presenta como un árbol de elementos de automatización relacionados. El cliente de Automatización de la interfaz de usuario puede estar interesado en una sola aplicación a la vez o en todo el árbol. El cliente de Automatización de la interfaz de usuario puede usar Automatización de la interfaz de usuario API para navegar por el árbol y leer o cambiar información en los elementos de automatización.
  • Automatización de la interfaz de usuario proveedores contribuyen a la información al árbol de Automatización de la interfaz de usuario, mediante la implementación de API que exponen los elementos de la interfaz de usuario que introdujeron como parte de su aplicación. Al crear un nuevo control, ahora debe actuar como participante en el escenario de proveedor de Automatización de la interfaz de usuario. Como proveedor, debe asegurarse de que todos los clientes de Automatización de la interfaz de usuario puedan usar el marco de Automatización de la interfaz de usuario para interactuar con el control con fines de accesibilidad y pruebas.

Normalmente hay API paralelas en el marco de Automatización de la interfaz de usuario: una API para clientes de Automatización de la interfaz de usuario y otra api con nombre similar para proveedores de Automatización de la interfaz de usuario. En la mayor parte, en este tema se tratan las API del proveedor de Automatización de la interfaz de usuario, y específicamente las clases e interfaces que permiten la extensibilidad del proveedor en ese marco de interfaz de usuario. En ocasiones, mencionamos Automatización de la interfaz de usuario API que usan los clientes de Automatización de la interfaz de usuario, para proporcionar alguna perspectiva o proporcionar una tabla de búsqueda que correlaciona las API de cliente y proveedor. Para obtener más información sobre la perspectiva del cliente, consulta Automatización de la interfaz de usuario Guía del programador de clientes.

Nota:

Automatización de la interfaz de usuario los clientes no suelen usar código administrado y normalmente no se implementan como una aplicación para UWP (normalmente son aplicaciones de escritorio). Automatización de la interfaz de usuario se basa en un estándar y no en una implementación o marco específicos. Muchos clientes de Automatización de la interfaz de usuario existentes, incluidos productos de tecnología de asistencia, como lectores de pantalla, usan interfaces del Modelo de objetos componentes (COM) para interactuar con Automatización de la interfaz de usuario, el sistema y las aplicaciones que se ejecutan en ventanas secundarias. Para obtener más información sobre las interfaces COM y cómo escribir un cliente de Automatización de la interfaz de usuario mediante COM, consulta Automatización de la interfaz de usuario Aspectos básicos.

Determinación del estado existente de Automatización de la interfaz de usuario compatibilidad con la clase de interfaz de usuario personalizada

Antes de intentar implementar un elemento del mismo nivel de automatización para un control personalizado, debe probar si la clase base y su sistema del mismo nivel de automatización ya proporcionan la compatibilidad de accesibilidad o automatización que necesita. En muchos casos, la combinación de las implementaciones frameworkElementAutomationPeer , elementos del mismo nivel específicos y los patrones que implementan pueden proporcionar una experiencia de accesibilidad básica pero satisfactoria. Si esto es cierto depende del número de cambios realizados en la exposición del modelo de objetos al control frente a su clase base. Además, esto depende de si las adiciones a la funcionalidad de clase base se correlacionan con los nuevos elementos de la interfaz de usuario del contrato de plantilla o la apariencia visual del control. En algunos casos, los cambios pueden introducir nuevos aspectos de la experiencia del usuario que requieren compatibilidad adicional de accesibilidad.

Incluso si el uso de la clase base del mismo nivel existente proporciona compatibilidad básica con la accesibilidad, sigue siendo un procedimiento recomendado definir un elemento del mismo nivel para que pueda notificar información precisa de ClassName para Automatización de la interfaz de usuario para escenarios de pruebas automatizadas. Esta consideración es especialmente importante si está escribiendo un control destinado al consumo de terceros.

Clases del mismo nivel de Automatización

La UWP se basa en las técnicas y convenciones de Automatización de la interfaz de usuario existentes usadas por marcos de interfaz de usuario de código administrado anteriores, como Windows Forms, Windows Presentation Foundation (WPF) y Microsoft Silverlight. Muchas de las clases de control y su función y propósito también tienen su origen en un marco de interfaz de usuario anterior.

Por convención, los nombres de clase del mismo nivel empiezan por el nombre de clase del control y terminan por "AutomationPeer". Por ejemplo, ButtonAutomationPeer es la clase del mismo nivel para la clase de control Button.

Nota:

Para los fines de este tema, tratamos las propiedades relacionadas con la accesibilidad como más importantes al implementar un elemento del mismo nivel de control. Pero para un concepto más general de soporte técnico de Automatización de la interfaz de usuario, debe implementar un elemento del mismo nivel de acuerdo con las recomendaciones documentadas por la Guía del programador del proveedor de Automatización de la interfaz de usuario y Automatización de la interfaz de usuario Aspectos básicos. Estos temas no tratan las API de AutomationPeer específicas que usarías para proporcionar la información en el marco de UWP para Automatización de la interfaz de usuario, pero describen las propiedades que identifican tu clase o proporcionan otra información o interacción.

Pares, patrones y tipos de control

Un patrón de control es una implementación de interfaz que expone un aspecto determinado de la funcionalidad de un control a un cliente de Automatización de la interfaz de usuario. Automatización de la interfaz de usuario clientes usan las propiedades y los métodos expuestos a través de un patrón de control para recuperar información sobre las funcionalidades del control o para manipular el comportamiento del control en tiempo de ejecución.

Los patrones de control proporcionan una manera de categorizar y exponer la funcionalidad de un control independientemente de su tipo o apariencia. Por ejemplo, un control que presenta una interfaz tabular usa el patrón de control Grid para exponer el número de filas y columnas de la tabla y para permitir que un cliente de Automatización de la interfaz de usuario recupere elementos de la tabla. Como otros ejemplos, el cliente de Automatización de la interfaz de usuario puede usar el patrón de control Invoke para los controles que se pueden invocar, como botones, y el patrón de control Scroll para los controles que tienen barras de desplazamiento, como cuadros de lista, vistas de lista o cuadros combinados. Cada patrón de control representa un tipo independiente de funcionalidad y los patrones de control se pueden combinar para describir el conjunto completo de funciones compatibles con un control determinado.

Los patrones de control se relacionan con la interfaz de usuario como interfaces relacionadas con los objetos COM. En COM, puedes consultar a un objeto para preguntar qué interfaces admite y después usar esas interfaces para acceder a la funcionalidad. En Automatización de la interfaz de usuario, los clientes de Automatización de la interfaz de usuario pueden consultar un Automatización de la interfaz de usuario para averiguar qué patrones de control admite y, a continuación, interactuar con el elemento y su control emparejado a través de las propiedades, métodos, eventos y estructuras expuestos por los patrones de control admitidos.

Uno de los principales propósitos de un sistema del mismo nivel de automatización es informar a un cliente Automatización de la interfaz de usuario que controla los patrones de interfaz de usuario que el elemento de interfaz de usuario puede admitir a través de su elemento del mismo nivel. Para ello, Automatización de la interfaz de usuario proveedores implementan nuevos elementos del mismo nivel que cambian el comportamiento del método GetPattern reemplazando el método GetPatternCore. Automatización de la interfaz de usuario clientes realizan llamadas que el proveedor de Automatización de la interfaz de usuario asigna a llamar a GetPattern. Automatización de la interfaz de usuario los clientes consultan cada patrón específico con el que quieren interactuar. Si el elemento del mismo nivel admite el patrón, devuelve una referencia de objeto a sí misma; de lo contrario, devuelve null. Si el valor devuelto no es NULL, el cliente de Automatización de la interfaz de usuario espera que pueda llamar a las API de la interfaz de patrón como cliente para interactuar con ese patrón de control.

Un tipo de control es una manera de definir ampliamente la funcionalidad de un control que representa el mismo nivel. Este es un concepto diferente al de un patrón de control porque mientras un patrón informa Automatización de la interfaz de usuario qué información puede obtener o qué acciones puede realizar a través de una interfaz determinada, el tipo de control existe un nivel por encima de eso. Cada tipo de control tiene instrucciones sobre estos aspectos de Automatización de la interfaz de usuario:

  • Automatización de la interfaz de usuario patrones de control: un tipo de control puede admitir más de un patrón, cada uno de los cuales representa una clasificación diferente de información o interacción. Cada tipo de control tiene un conjunto de patrones de control que el control debe admitir, un conjunto opcional y un conjunto que el control no debe admitir.
  • Automatización de la interfaz de usuario valores de propiedad: cada tipo de control tiene un conjunto de propiedades que el control debe admitir. Estas son las propiedades generales, como se describe en Automatización de la interfaz de usuario Información general sobre propiedades, no las que son específicas del patrón.
  • Automatización de la interfaz de usuario eventos: cada tipo de control tiene un conjunto de eventos que el control debe admitir. De nuevo, estas son generales, no específicas del patrón, como se describe en información general sobre eventos de Automatización de la interfaz de usuario.
  • Automatización de la interfaz de usuario estructura de árbol: cada tipo de control define cómo debe aparecer el control en la estructura de árbol de Automatización de la interfaz de usuario.

Independientemente de cómo se implementen los sistemas del mismo nivel de automatización para el marco, Automatización de la interfaz de usuario funcionalidad de cliente no está vinculada a UWP y, de hecho, es probable que los clientes Automatización de la interfaz de usuario existentes, como las tecnologías de asistencia, usen otros modelos de programación, como COM. En COM, los clientes pueden consultarInterface para la interfaz de patrón de control COM que implementa el patrón solicitado o el marco de Automatización de la interfaz de usuario general para propiedades, eventos o examen de árboles. Para los patrones, el marco de Automatización de la interfaz de usuario calcula las referencias de ese código de interfaz en el código de UWP que se ejecuta en el proveedor de Automatización de la interfaz de usuario de la aplicación y en el mismo nivel correspondiente.

Al implementar patrones de control para un marco de código administrado, como una aplicación para UWP mediante C# o Microsoft Visual Basic, puedes usar interfaces de .NET Framework para representar estos patrones en lugar de usar la representación de la interfaz COM. Por ejemplo, la interfaz de patrón Automatización de la interfaz de usuario para una implementación del proveedor de Microsoft .NET del patrón Invoke es IInvokeProvider.

Para obtener una lista de patrones de control, interfaces de proveedor y su propósito, consulte Patrones e interfaces de control. Para obtener la lista de los tipos de control, consulte Automatización de la interfaz de usuario Información general sobre los tipos de control.

Instrucciones para implementar patrones de control

Los patrones de control y lo que están diseñados para forman parte de una definición mayor del marco de Automatización de la interfaz de usuario y no solo se aplican a la compatibilidad de accesibilidad para una aplicación para UWP. Al implementar un patrón de control, debe asegurarse de implementarlo de forma que coincida con las instrucciones que se documentan en estos documentos y también en la especificación de Automatización de la interfaz de usuario. Si busca instrucciones, normalmente puede usar la documentación de Microsoft y no tendrá que hacer referencia a la especificación. Aquí se documentan instrucciones para cada patrón: Implementación de Automatización de la interfaz de usuario patrones de control. Observará que cada tema de esta área tiene una sección "Directrices y convenciones de implementación" y la sección "Miembros necesarios". Normalmente, las instrucciones hacen referencia a API específicas de la interfaz de patrón de control pertinente en la referencia Interfaces de patrón de control para proveedores . Estas interfaces son las interfaces nativas o COM (y sus API usan sintaxis de estilo COM). Pero todo lo que ves tiene un equivalente en el espacio de nombres Windows.UI.Xaml.Automation.Provider.

Si usa los elementos del mismo nivel de automatización predeterminados y amplía su comportamiento, esos elementos del mismo nivel ya se han escrito conforme a las directrices de Automatización de la interfaz de usuario. Si admiten patrones de control, puede basarse en ese patrón compatible con las instrucciones de Implementación de patrones de control Automatización de la interfaz de usuario. Si un elemento del mismo nivel de control informa de que es representativo de un tipo de control definido por Automatización de la interfaz de usuario, la guía documentada en Compatibilidad con Automatización de la interfaz de usuario tipos de control se ha seguido de ese mismo nivel.

Sin embargo, es posible que necesite instrucciones adicionales para los patrones de control o los tipos de control para seguir las recomendaciones de Automatización de la interfaz de usuario en la implementación del mismo nivel. Esto sería especialmente cierto si estás implementando compatibilidad con patrones o tipos de control que aún no existen como una implementación predeterminada en un control de UWP. Por ejemplo, el patrón de anotaciones no se implementa en ninguno de los controles XAML predeterminados. Pero es posible que tenga una aplicación que use anotaciones ampliamente y, por lo tanto, quiera exponer esa funcionalidad para que sea accesible. En este escenario, el mismo nivel debe implementar IAnnotationProvider y probablemente debería informarse como el tipo de control Document con las propiedades adecuadas para indicar que los documentos admiten anotaciones.

Se recomienda usar las instrucciones que se ven para los patrones en Implementación de patrones de control o tipos de control Automatización de la interfaz de usuario en Compatibilidad con tipos de control Automatización de la interfaz de usuario como orientación e instrucciones generales. Incluso puede intentar seguir algunos de los vínculos de API para las descripciones y los comentarios sobre el propósito de las API. Pero para conocer los detalles de la sintaxis necesarios para la programación de aplicaciones para UWP, busque la API equivalente en el espacio de nombres Windows.UI.Xaml.Automation.Provider y use esas páginas de referencia para obtener más información.

Clases del mismo nivel de automatización integradas

En general, los elementos implementan una clase del mismo nivel de automatización si aceptan actividad de interfaz de usuario del usuario, o si contienen información necesaria para los usuarios de tecnologías de asistencia que representan la interfaz de usuario interactiva o significativa de las aplicaciones. No todos los elementos visuales de UWP tienen sistemas del mismo nivel de automatización. Algunos ejemplos de clases que implementan elementos del mismo nivel de automatización son Button y TextBox. Algunos ejemplos de clases que no implementan elementos del mismo nivel de automatización son Border y clases basadas en Panel, como Grid y Canvas. Un Panel no tiene ningún elemento del mismo nivel porque proporciona un comportamiento de diseño que es solo visual. No hay ninguna manera relevante de accesibilidad para que el usuario interactúe con un Panel. Los elementos secundarios que contiene un Panel se notifican en su lugar a Automatización de la interfaz de usuario árboles como elementos secundarios del siguiente elemento primario disponible en el árbol que tiene una representación de elemento o del mismo nivel.

límites de proceso de Automatización de la interfaz de usuario y UWP

Normalmente, Automatización de la interfaz de usuario código de cliente que accede a una aplicación para UWP se ejecuta fuera de proceso. La infraestructura del marco de Automatización de la interfaz de usuario permite que la información entre el límite del proceso. Este concepto se explica con más detalle en Automatización de la interfaz de usuario Aspectos básicos.

OnCreateAutomationPeer

Todas las clases que derivan de UIElement contienen el método virtual protegido OnCreateAutomationPeer. La secuencia de inicialización de objetos para los elementos del mismo nivel de automatización llama a OnCreateAutomationPeer para obtener el objeto del mismo nivel de automatización para cada control y, por tanto, construir un árbol de Automatización de la interfaz de usuario para el uso en tiempo de ejecución. Automatización de la interfaz de usuario código puede usar el elemento del mismo nivel para obtener información sobre las características y características de un control y simular el uso interactivo mediante sus patrones de control. Un control personalizado que admita la automatización debe invalidar OnCreateAutomationPeer y devolver una instancia de una clase que derive de AutomationPeer. Por ejemplo, si un control personalizado deriva de la clase ButtonBase, el objeto devuelto por OnCreateAutomationPeer debe derivar de ButtonBaseAutomationPeer.

Si está escribiendo una clase de control personalizada y pretende proporcionar también un nuevo par de automatización, debe invalidar el método OnCreateAutomationPeer para el control personalizado para que devuelva una nueva instancia del mismo nivel. La clase del mismo nivel debe derivarse directa o indirectamente de AutomationPeer.

Por ejemplo, el código siguiente declara que el control NumericUpDown personalizado debe usar el elemento del mismo nivel NumericUpDownPeer para Automatización de la interfaz de usuario propósitos.

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);
    }
};

Nota:

La implementación de OnCreateAutomationPeer no debe hacer nada más que inicializar una nueva instancia del mismo nivel de automatización personalizada, pasar el control de llamada como propietario y devolver esa instancia. No intente lógica adicional en este método. En concreto, cualquier lógica que pueda provocar la destrucción de AutomationPeer dentro de la misma llamada puede dar lugar a un comportamiento inesperado en tiempo de ejecución.

En implementaciones típicas de OnCreateAutomationPeer, el propietario se especifica como este o me porque la invalidación del método está en el mismo ámbito que el resto de la definición de clase de control.

La definición de clase del mismo nivel real se puede realizar en el mismo archivo de código que el control o en un archivo de código independiente. Todas las definiciones del mismo nivel existen en el espacio de nombres Windows.UI.Xaml.Automation.Peers que es un espacio de nombres independiente de los controles para los que proporcionan elementos del mismo nivel. También puede declarar los elementos del mismo nivel en espacios de nombres independientes, siempre que haga referencia a los espacios de nombres necesarios para la llamada al método OnCreateAutomationPeer.

Elección de la clase base del mismo nivel correcta

Asegúrese de que AutomationPeer se deriva de una clase base que proporciona la mejor coincidencia para la lógica del mismo nivel existente de la clase de control de la que deriva. En el caso del ejemplo anterior, dado que NumericUpDown deriva de RangeBase, hay una clase RangeBaseAutomationPeer disponible en la que debe basar el elemento del mismo nivel. Mediante el uso de la clase del mismo nivel coincidente más cercana en paralelo a cómo se deriva el propio control, puede evitar invalidar al menos algunas de las funciones de IRangeValueProvider porque la clase del mismo nivel base ya la implementa.

La clase Control base no tiene una clase del mismo nivel correspondiente. Si necesita una clase del mismo nivel para corresponder a un control personalizado que deriva de Control, derive la clase del mismo nivel personalizada de FrameworkElementAutomationPeer.

Si deriva directamente de ContentControl , esa clase no tiene ningún comportamiento del mismo nivel de automatización predeterminado porque no hay ninguna implementación onCreateAutomationPeer que haga referencia a una clase del mismo nivel. Por lo tanto, asegúrese de implementar OnCreateAutomationPeer para usar su propio elemento del mismo nivel o para usar FrameworkElementAutomationPeer como el mismo nivel si ese nivel de compatibilidad de accesibilidad es adecuado para su control.

Nota:

Normalmente no deriva de AutomationPeer en lugar de FrameworkElementAutomationPeer. Si se deriva directamente de AutomationPeer , necesitará duplicar una gran cantidad de compatibilidad básica de accesibilidad que, de lo contrario, provendría de FrameworkElementAutomationPeer.

Inicialización de una clase del mismo nivel personalizada

El mismo nivel de automatización debe definir un constructor seguro para tipos que use una instancia del control propietario para la inicialización base. En el ejemplo siguiente, la implementación pasa el valor de propietario a la base RangeBaseAutomationPeer y, en última instancia, es frameworkElementAutomationPeer que realmente usa el propietario para establecer 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);

Métodos principales de AutomationPeer

Por motivos de infraestructura de UWP, los métodos reemplazables de un elemento del mismo nivel de automatización forman parte de un par de métodos: el método de acceso público que el proveedor de Automatización de la interfaz de usuario usa como punto de reenvío para Automatización de la interfaz de usuario clientes y el método de personalización "Core" protegido que una clase para UWP puede invalidar para influir en el comportamiento. El par de métodos se conecta de forma predeterminada de forma que la llamada al método de acceso siempre invoca el método paralelo "Core" que tiene la implementación del proveedor, o como reserva, invoca una implementación predeterminada de las clases base.

Al implementar un elemento del mismo nivel para un control personalizado, invalide cualquiera de los métodos "Core" de la clase del mismo nivel de automatización base donde desea exponer el comportamiento que es único para el control personalizado. Automatización de la interfaz de usuario código obtiene información sobre el control llamando a métodos públicos de la clase del mismo nivel. Para proporcionar información sobre el control, invalide cada método con un nombre que termina con "Core" cuando la implementación y el diseño del control crean escenarios de accesibilidad u otros escenarios de Automatización de la interfaz de usuario que difieren de lo que admite la clase del mismo nivel de automatización base.

Como mínimo, siempre que defina una nueva clase del mismo nivel, implemente el método GetClassNameCore , como se muestra en el ejemplo siguiente.

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

Nota:

Es posible que quiera almacenar las cadenas como constantes en lugar de directamente en el cuerpo del método, pero eso le corresponde. Para GetClassNameCore, no es necesario localizar esta cadena. La propiedad LocalizedControlType se usa cada vez que un cliente de Automatización de la interfaz de usuario necesita una cadena localizada, no ClassName.

GetAutomationControlType

Algunas tecnologías de asistencia usan el valor GetAutomationControlType directamente al notificar las características de los elementos de un árbol de Automatización de la interfaz de usuario, como información adicional más allá del nombre de Automatización de la interfaz de usuario. Si el control es significativamente diferente del control del que deriva y desea informar de un tipo de control diferente de lo que notifica la clase del mismo nivel base usada por el control, debe implementar un elemento del mismo nivel e invalidar GetAutomationControlTypeCore en la implementación del mismo nivel. Esto es especialmente importante si se deriva de una clase base generalizada, como ItemsControl o ContentControl, donde el elemento del mismo nivel base no proporciona información precisa sobre el tipo de control.

La implementación de GetAutomationControlTypeCore describe el control devolviendo un valor AutomationControlType. Aunque puede devolver AutomationControlType.Custom, debe devolver uno de los tipos de control más específicos si describe con precisión los escenarios principales del control. Este es un ejemplo.

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

Nota:

A menos que especifique AutomationControlType.Custom, no es necesario implementar GetLocalizedControlTypeCore para proporcionar un valor de propiedad LocalizedControlType a los clientes. Automatización de la interfaz de usuario infraestructura común proporciona cadenas traducidas para cada posible Valor automationControlType distinto de AutomationControlType.Custom.

GetPattern y GetPatternCore

La implementación del mismo nivel de GetPatternCore devuelve el objeto que admite el patrón solicitado en el parámetro de entrada. En concreto, un cliente de Automatización de la interfaz de usuario llama a un método que se reenvía al método GetPattern del proveedor y especifica un valor de enumeración PatternInterface que asigna un nombre al patrón solicitado. La invalidación de GetPatternCore debe devolver el objeto que implementa el patrón especificado. Ese objeto es el mismo elemento del mismo nivel, ya que el mismo nivel debe implementar la interfaz de patrón correspondiente cada vez que informa de que admite un patrón. Si el mismo nivel no tiene una implementación personalizada de un patrón, pero sabe que la base del mismo nivel implementa el patrón, puede llamar a la implementación del tipo base de GetPatternCore desde getPatternCore. GetPatternCore de un mismo nivel debe devolver null si el mismo nivel no admite un patrón. Sin embargo, en lugar de devolver null directamente desde la implementación, normalmente se basaría en la llamada a la implementación base para devolver null para cualquier patrón no admitido.

Cuando se admite un patrón, la implementación getPatternCore puede devolver esto o me. La expectativa es que el cliente de Automatización de la interfaz de usuario convierta el valor devuelto GetPattern en la interfaz de patrón solicitada siempre que no sea NULL.

Si una clase del mismo nivel hereda de otro mismo nivel y la clase base ya controla todos los informes de patrones y soporte necesarios, la implementación de GetPatternCore no es necesaria. Por ejemplo, si va a implementar un control de intervalo que deriva de RangeBase y el elemento del mismo nivel deriva de RangeBaseAutomationPeer, ese par se devuelve a sí mismo para PatternInterface.RangeValue y tiene implementaciones de trabajo de la interfaz IRangeValueProvider que admite el patrón.

Aunque no es el código literal, este ejemplo se aproxima a la implementación de GetPatternCore ya presente en RangeBaseAutomationPeer.

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

Si va a implementar un elemento del mismo nivel en el que no tiene toda la compatibilidad que necesita desde una clase del mismo nivel base, o desea cambiar o agregar al conjunto de patrones heredados base que el mismo nivel puede admitir, debe invalidar GetPatternCore para permitir que los clientes de Automatización de la interfaz de usuario usen los patrones.

Para obtener una lista de los patrones de proveedor que están disponibles en la implementación de UWP de Automatización de la interfaz de usuario compatibilidad, consulta Windows.UI.Xaml.Automation.Provider. Cada patrón de este tipo tiene un valor correspondiente de la enumeración PatternInterface, que es cómo Automatización de la interfaz de usuario clientes solicitan el patrón en una llamada a GetPattern.

Un elemento del mismo nivel puede notificar que admite más de un patrón. Si es así, la invalidación debe incluir la lógica de ruta de acceso de devolución para cada valor de PatternInterface compatible y devolver el elemento del mismo nivel en cada caso coincidente. Se espera que el autor de la llamada solicite solo una interfaz a la vez, y depende del autor de la llamada convertir a la interfaz esperada.

Este es un ejemplo de invalidación de GetPatternCore para un elemento del mismo nivel personalizado. Informa de la compatibilidad con dos patrones, IRangeValueProvider e IToggleProvider. El control aquí es un control de pantalla multimedia que puede mostrarse como pantalla completa (el modo de alternancia) y que tiene una barra de progreso dentro de la que los usuarios pueden seleccionar una posición (el control de intervalo). Este código procede del ejemplo de accesibilidad XAML.

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

Patrones de reenvío desde sub elementos

Una implementación del método GetPatternCore también puede especificar un sub-elemento o parte como proveedor de patrones para su host. En este ejemplo se imita cómo ItemsControl transfiere el control de patrones de desplazamiento al mismo nivel de su control ScrollViewer interno. Para especificar un subelemento para el control de patrones, este código obtiene el objeto de subelemento, crea un elemento del mismo nivel para el subelemento mediante el método FrameworkElementAutomationPeer.CreatePeerForElement y devuelve el nuevo elemento del mismo nivel.

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);
}

Otros métodos principales

Es posible que el control necesite admitir equivalentes de teclado para escenarios principales; para obtener más información sobre por qué podría ser necesario, consulta Accesibilidad del teclado. La implementación de la compatibilidad con claves es necesariamente parte del código de control y no del código del mismo nivel porque forma parte de la lógica de un control, pero la clase del mismo nivel debe invalidar los métodos GetAcceleratorKeyCore y GetAccessKeyCore para informar a Automatización de la interfaz de usuario clientes que se usan las claves. Tenga en cuenta que es posible que las cadenas que notifican información clave deban localizarse y, por lo tanto, provengan de recursos, no cadenas codificadas de forma rígida.

Si proporciona un elemento del mismo nivel para una clase que admite una colección, es mejor derivar de las clases funcionales y las clases del mismo nivel que ya tienen ese tipo de compatibilidad con la recopilación. Si no lo puede hacer, los elementos del mismo nivel para los controles que mantienen colecciones secundarias pueden tener que invalidar el método del mismo nivel relacionado con la colección GetChildrenCore para notificar correctamente las relaciones de elementos primarios y secundarios al árbol de Automatización de la interfaz de usuario.

Implemente los métodos IsContentElementCore e IsControlElementCore para indicar si el control contiene contenido de datos o cumple un rol interactivo en la interfaz de usuario (o ambos). De forma predeterminada, ambos métodos devuelven true. Esta configuración mejora la facilidad de uso de tecnologías de asistencia, como los lectores de pantalla, que pueden usar estos métodos para filtrar el árbol de automatización. Si el método GetPatternCore transfiere el control de patrones a un elemento secundario del mismo nivel, el método IsControlElementCore del mismo nivel del subelemento puede devolver false para ocultar el subelemento del mismo nivel del árbol de automatización.

Algunos controles pueden admitir escenarios de etiquetado, donde una parte de etiqueta de texto proporciona información para una parte que no es de texto o un control está pensado para estar en una relación de etiquetado conocida con otro control de la interfaz de usuario. Si es posible proporcionar un comportamiento útil basado en clases, puede invalidar GetLabeledByCore para proporcionar este comportamiento.

GetBoundingRectangleCore y GetClickablePointCore se usan principalmente para escenarios de pruebas automatizadas. Si desea admitir pruebas automatizadas para el control, es posible que quiera invalidar estos métodos. Esto puede ser deseado para los controles de tipo de intervalo, donde no se puede sugerir un único punto porque el usuario hace clic en el espacio de coordenadas tiene un efecto diferente en un intervalo. Por ejemplo, el elemento del mismo nivel de automatización de ScrollBar predeterminado invalida GetClickablePointCore para devolver un valor point "not a number".

GetLiveSettingCore influye en el valor predeterminado del control para el valor de LiveSetting para Automatización de la interfaz de usuario. Es posible que desee invalidar esto si desea que el control devuelva un valor distinto de AutomationLiveSetting.Off. Para obtener más información sobre lo que representa LiveSetting, consulta AutomationProperties.LiveSetting.

Puede invalidar GetOrientationCore si el control tiene una propiedad de orientación settable que se puede asignar a AutomationOrientation. Las clases ScrollBarAutomationPeer y SliderAutomationPeer lo hacen.

Implementación base en FrameworkElementAutomationPeer

La implementación base de FrameworkElementAutomationPeer proporciona algunas Automatización de la interfaz de usuario información que se puede interpretar desde varias propiedades de diseño y comportamiento definidas en el nivel de marco.

Nota:

Los elementos del mismo nivel de UWP predeterminados implementan un comportamiento mediante código nativo interno que implementa UWP, no necesariamente mediante código UWP real. No podrá ver el código o la lógica de la implementación a través de la reflexión de Common Language Runtime (CLR) u otras técnicas. Tampoco verá páginas de referencia distintas para invalidaciones específicas de subclases del comportamiento del mismo nivel base. Por ejemplo, puede haber un comportamiento adicional para GetNameCore de un TextBoxAutomationPeer, que no se describirá en la página de referencia AutomationPeer.GetNameCore y no hay ninguna página de referencia para TextBoxAutomationPeer.GetNameCore. Ni siquiera hay una página de referencia TextBoxAutomationPeer.GetNameCore . En su lugar, lea el tema de referencia de la clase del mismo nivel más inmediato y busque notas de implementación en la sección Comentarios.

Elementos del mismo nivel y AutomationProperties

El mismo nivel de automatización debe proporcionar los valores predeterminados adecuados para la información relacionada con la accesibilidad del control. Tenga en cuenta que cualquier código de aplicación que use el control puede invalidar parte de ese comportamiento mediante la inclusión de valores de propiedad adjunta automationProperties en instancias de control. Los autores de llamadas pueden hacerlo para los controles predeterminados o para los controles personalizados. Por ejemplo, el código XAML siguiente crea un botón que tiene dos propiedades de Automatización de la interfaz de usuario personalizadas:<Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>

Para obtener más información sobre las propiedades adjuntas AutomationProperties, consulte Información de accesibilidad básica.

Algunos de los métodos AutomationPeer existen debido al contrato general de cómo se espera que los proveedores de Automatización de la interfaz de usuario informen de información, pero estos métodos no se implementan normalmente en elementos del mismo nivel de control. Esto se debe a que se espera que los valores de AutomationProperties se proporcionen mediante los valores de AutomationProperties aplicados al código de la aplicación que usa los controles de una interfaz de usuario específica. Por ejemplo, la mayoría de las aplicaciones definirían la relación de etiquetado entre dos controles diferentes en la interfaz de usuario aplicando un valor AutomationProperties.LabeledBy. Sin embargo, LabeledByCore se implementa en determinados elementos del mismo nivel que representan relaciones de datos o elementos en un control, como usar una parte de encabezado para etiquetar un elemento de campo de datos, etiquetar elementos con sus contenedores o escenarios similares.

Implementación de patrones

Echemos un vistazo a cómo escribir un elemento del mismo nivel para un control que implementa un comportamiento de contraer expansión mediante la implementación de la interfaz de patrón de control para expandir y contraer. El elemento del mismo nivel debe habilitar la accesibilidad para el comportamiento de expansión y contraer devolviéndose cada vez que se llama a GetPattern con un valor de PatternInterface.ExpandCollapse. A continuación, el elemento del mismo nivel debe heredar la interfaz del proveedor para ese patrón (IExpandCollapseProvider) y proporcionar implementaciones para cada uno de los miembros de esa interfaz de proveedor. En este caso, la interfaz tiene tres miembros para invalidar: Expand, Collapse, ExpandCollapseState.

Resulta útil planear la accesibilidad en el diseño de api de la propia clase. Siempre que tenga un comportamiento que se solicite potencialmente como resultado de interacciones típicas con un usuario que trabaja en la interfaz de usuario o a través de un patrón de proveedor de automatización, proporcione un único método al que pueda llamar la respuesta de la interfaz de usuario o el patrón de automatización. Por ejemplo, si el control tiene partes de botón que tienen controladores de eventos cableados que pueden expandir o contraer el control, y tiene equivalentes de teclado para esas acciones, haga que estos controladores de eventos llamen al mismo método que llama desde el cuerpo de las implementaciones Expand o Collapse para IExpandCollapseProvider en el mismo nivel. El uso de un método lógico común también puede ser una manera útil de asegurarse de que los estados visuales del control se actualizan para mostrar el estado lógico de forma uniforme, independientemente de cómo se invoque el comportamiento.

Una implementación típica es que las API del proveedor llaman primero al propietario para acceder a la instancia de control en tiempo de ejecución. A continuación, se puede llamar a los métodos de comportamiento necesarios en ese objeto.

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

Una implementación alternativa es que el propio control puede hacer referencia a su elemento del mismo nivel. Este es un patrón común si está generando eventos de automatización desde el control, ya que el método RaiseAutomationEvent es un método del mismo nivel.

eventos de Automatización de la interfaz de usuario

Los eventos de Automatización de la interfaz de usuario pueden clasificarse de la siguiente manera.

Evento Descripción
Cambio de propiedad Se desencadena cuando cambia una propiedad de un elemento Automatización de la interfaz de usuario o patrón de control. Por ejemplo, si un cliente necesita supervisar el control de casilla de una aplicación, puede registrarse para escuchar un evento de cambio de propiedad en la propiedad ToggleState. Cuando se activa o desactiva el control de casilla, el proveedor activa el evento y el cliente puede actuar según sea necesario.
Acción de elemento Se desencadena cuando un cambio en la interfaz de usuario resulta de la actividad de usuario o mediante programación; Por ejemplo, cuando se hace clic en un botón o se invoca a través del patrón Invoke .
Cambio de estructura Se desencadena cuando cambia la estructura del árbol de Automatización de la interfaz de usuario. La estructura cambia cuando se hacen visibles, ocultan o quitan elementos nuevos de la interfaz de usuario en el escritorio.
Cambio global Se desencadena cuando se producen acciones de interés global para el cliente, como cuando el foco cambia de un elemento a otro, o cuando se cierra una ventana secundaria. Algunos eventos no implican necesariamente un cambio en el estado de la UI. Por ejemplo, si el usuario ficha en un campo de entrada de texto y, a continuación, hace clic en un botón para actualizar el campo, se desencadena un evento TextChanged incluso si el usuario no cambió realmente el texto. Al procesar un evento, puede ser necesario que la aplicación cliente compruebe si realmente se ha producido un cambio antes de realizar cualquier acción.

Identificadores automationEvents

Automatización de la interfaz de usuario eventos se identifican mediante Valores de AutomationEvents. Los valores de la enumeración identifican de forma única el tipo de evento.

Provocar eventos

Automatización de la interfaz de usuario clientes pueden suscribirse a eventos de automatización. En el modelo del mismo nivel de automatización, los elementos del mismo nivel para los controles personalizados deben notificar los cambios en el estado de control que son relevantes para la accesibilidad mediante una llamada al método RaiseAutomationEvent. Del mismo modo, cuando cambia una clave Automatización de la interfaz de usuario valor de propiedad, los elementos del mismo nivel de control personalizados deben llamar al método RaisePropertyChangedEvent.

En el ejemplo de código siguiente se muestra cómo obtener el objeto del mismo nivel desde el código de definición de control y llamar a un método para desencadenar un evento desde ese mismo nivel. Como optimización, el código determina si hay agentes de escucha para este tipo de evento. Desencadenar el evento y crear el objeto del mismo nivel solo cuando hay agentes de escucha evita una sobrecarga innecesaria y ayuda a que el control siga respondiendo.

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

Navegación del mismo nivel

Después de localizar un elemento del mismo nivel de automatización, un cliente de Automatización de la interfaz de usuario puede navegar por la estructura del mismo nivel de una aplicación llamando a los métodos GetChildren y GetParent del objeto del mismo nivel. La navegación entre los elementos de la interfaz de usuario dentro de un control es compatible con la implementación del mismo nivel del método GetChildrenCore. El sistema Automatización de la interfaz de usuario llama a este método para crear un árbol de elementos secundarios contenidos en un control; por ejemplo, elementos de lista en un cuadro de lista. El método GetChildrenCore predeterminado en FrameworkElementAutomationPeer recorre el árbol visual de elementos para compilar el árbol de elementos del mismo nivel de automatización. Los controles personalizados pueden invalidar este método para exponer una representación diferente de los elementos secundarios a los clientes de automatización, devolviendo los elementos del mismo nivel de automatización que transmiten información o permiten la interacción del usuario.

Compatibilidad de automatización nativa con patrones de texto

Algunos de los elementos del mismo nivel predeterminados de automatización de aplicaciones para UWP proporcionan compatibilidad con patrones de control para el patrón de texto (PatternInterface.Text). Pero proporcionan esta compatibilidad a través de métodos nativos y los elementos del mismo nivel implicados no anotarán la interfaz ITextProvider en la herencia (administrada). Sin embargo, si un cliente de Automatización de la interfaz de usuario administrado o no administrado consulta el mismo nivel para los patrones, notificará la compatibilidad con el patrón de texto y proporcionará un comportamiento para las partes del patrón cuando se llame a las API de cliente.

Si quieres derivar de uno de los controles de texto de la aplicación para UWP y también crear un elemento del mismo nivel personalizado que derive de uno de los elementos del mismo nivel relacionados con el texto, consulta las secciones Comentarios del mismo nivel para obtener más información sobre cualquier compatibilidad de nivel nativo con patrones. Puede acceder al comportamiento base nativo en el mismo nivel personalizado si llama a la implementación base desde las implementaciones de la interfaz del proveedor administrado, pero es difícil modificar lo que hace la implementación base porque las interfaces nativas del mismo nivel y su control propietario no se exponen. Por lo general, debe usar las implementaciones base tal como está (solo llamada a base) o reemplazar completamente la funcionalidad por su propio código administrado y no llamar a la implementación base. Este último es un escenario avanzado, necesitará estar familiarizado con el marco de servicios de texto que usa el control para admitir los requisitos de accesibilidad al usar ese marco.

AutomationProperties.AccessibilityView

Además de proporcionar un elemento del mismo nivel personalizado, también puedes ajustar la representación de la vista de árbol para cualquier instancia de control estableciendo AutomationProperties.AccessibilityView en XAML. Esto no se implementa como parte de una clase del mismo nivel, pero lo mencionaremos aquí porque es alemán para la compatibilidad general de accesibilidad para controles personalizados o para plantillas que personalice.

El escenario principal para usar AutomationProperties.AccessibilityView es omitir deliberadamente determinados controles de una plantilla de las vistas de Automatización de la interfaz de usuario, ya que no contribuyen significativamente a la vista de accesibilidad de todo el control. Para evitar esto, establezca AutomationProperties.AccessibilityView en "Raw".

Iniciar excepciones de sistemas del mismo nivel de automatización

Las API que va a implementar para la compatibilidad con el mismo nivel de automatización pueden producir excepciones. Se espera que los clientes de Automatización de la interfaz de usuario que escuchan sean lo suficientemente sólidos como para continuar después de que se produzcan la mayoría de las excepciones. Con toda probabilidad de que el agente de escucha examine un árbol de automatización todo hacia arriba que incluya aplicaciones distintas de las suyas, y es un diseño de cliente inaceptable para reducir todo el cliente solo porque una área del árbol produjo una excepción basada en el mismo nivel cuando el cliente llamó a sus API.

En el caso de los parámetros que se pasan al mismo nivel, es aceptable validar la entrada y, por ejemplo, iniciar ArgumentNullException si se pasó null y no es un valor válido para la implementación. Sin embargo, si hay operaciones posteriores realizadas por el mismo nivel, recuerde que las interacciones del mismo nivel con el control de hospedaje tienen algo de un carácter asincrónico para ellos. Todo lo que un elemento del mismo nivel no bloquee necesariamente el subproceso de interfaz de usuario en el control (y probablemente no debería hacerlo). Por lo tanto, podría tener situaciones en las que un objeto estaba disponible o tenía determinadas propiedades cuando se creó el mismo nivel o cuando se llamó por primera vez a un método del mismo nivel de automatización, pero mientras tanto el estado del control ha cambiado. En estos casos, hay dos excepciones dedicadas que un proveedor puede producir:

  • Inicie ElementNotAvailableException si no puede acceder al propietario del mismo nivel o a un elemento del mismo nivel relacionado basado en la información original que se pasó a la API. Por ejemplo, es posible que tenga un elemento del mismo nivel que intente ejecutar sus métodos, pero el propietario se ha quitado de la interfaz de usuario, como un cuadro de diálogo modal que se ha cerrado. Para un cliente non-.NET, esto se asigna a UIA_E_ELEMENTNOTAVAILABLE.
  • Inicie ElementNotEnabledException si todavía hay un propietario, pero ese propietario está en un modo como IsEnabled=false que bloquea algunos de los cambios programáticos específicos que el mismo nivel está intentando realizar. Para un cliente de non-.NET, esto se asigna a UIA_E_ELEMENTNOTENABLED.

Además de esto, los elementos del mismo nivel deben ser relativamente conservadores con respecto a las excepciones que inician desde su compatibilidad del mismo nivel. La mayoría de los clientes no podrán controlar excepciones de elementos del mismo nivel y convertirlas en opciones accionables que sus usuarios puedan realizar al interactuar con el cliente. Por lo tanto, a veces, una operación no operativa y la detección de excepciones sin volver a iniciarse dentro de las implementaciones del mismo nivel, es una estrategia mejor que iniciar excepciones cada vez que un elemento del mismo nivel intenta hacer no funciona. Tenga en cuenta también que la mayoría de los clientes Automatización de la interfaz de usuario no están escritos en código administrado. La mayoría se escriben en COM y solo comprueban S_OK en un HRESULT cada vez que llaman a un método de cliente Automatización de la interfaz de usuario que termina accediendo al mismo nivel.