Partage via


Homologues d’automatisation personnalisés

Décrit le concept d’homologues d’automatisation pour Microsoft UI Automation et explique comment vous pouvez fournir une prise en charge de l’automatisation pour votre propre classe d’interface utilisateur personnalisée.

UI Automation fournit une infrastructure que les clients Automation peuvent utiliser pour examiner ou exploiter les interfaces utilisateur d’une variété de plateformes et d’infrastructures d’interface utilisateur. Si vous écrivez une application Windows, les classes que vous utilisez pour votre interface utilisateur fournissent déjà la prise en charge d’UI Automation. Vous pouvez dériver de classes existantes non scellées pour définir un nouveau type de contrôle d’interface utilisateur ou de classe de prise en charge. Dans le processus de ce processus, votre classe peut ajouter un comportement qui doit avoir une prise en charge de l’accessibilité, mais que la prise en charge UI Automation par défaut ne couvre pas. Dans ce cas, vous devez étendre la prise en charge d’UI Automation existante en dérivant de la classe AutomationPeer utilisée par l’implémentation de base, en ajoutant toute prise en charge nécessaire à votre implémentation homologue et en informant l’infrastructure de contrôle d’application Windows qu’elle doit créer votre nouvel homologue.

UI Automation permet non seulement les applications d’accessibilité et les technologies d’assistance, telles que les lecteurs d’écran, mais également le code d’assurance qualité (test). Dans les deux scénarios, les clients UI Automation peuvent examiner les éléments de l’interface utilisateur et simuler l’interaction utilisateur avec votre application à partir d’un autre code en dehors de votre application. Pour plus d’informations sur UI Automation sur toutes les plateformes et dans sa signification plus large, consultez vue d’ensemble d’UI Automation.

Il existe deux audiences distinctes qui utilisent l’infrastructure UI Automation.

  • Les clients UI Automation appellent les API UI Automation pour en savoir plus sur l’ensemble de l’interface utilisateur actuellement affichée à l’utilisateur. Par exemple, une technologie d’assistance telle qu’un lecteur d’écran agit comme un client UI Automation. L’interface utilisateur est présentée sous la forme d’une arborescence d’éléments d’automatisation associés. Le client UI Automation peut s’intéresser à une seule application à la fois ou dans l’arborescence entière. Le client UI Automation peut utiliser les API UI Automation pour naviguer dans l’arborescence et lire ou modifier des informations dans les éléments Automation.
  • Les fournisseurs UI Automation contribuent aux informations de l’arborescence UI Automation, en implémentant des API qui exposent les éléments de l’interface utilisateur qu’ils ont introduits dans le cadre de leur application. Lorsque vous créez un contrôle, vous devez maintenant agir en tant que participant au scénario du fournisseur UI Automation. En tant que fournisseur, vous devez vous assurer que tous les clients UI Automation peuvent utiliser l’infrastructure UI Automation pour interagir avec votre contrôle à des fins d’accessibilité et de test.

En règle générale, il existe des API parallèles dans l’infrastructure UI Automation : une API pour les clients UI Automation et une autre, également nommée API pour les fournisseurs UI Automation. Pour la plupart, cette rubrique traite des API pour le fournisseur UI Automation, et plus précisément les classes et interfaces qui permettent l’extensibilité du fournisseur dans cette infrastructure d’interface utilisateur. Parfois, nous mentionnons les API UI Automation que les clients UI Automation utilisent, pour fournir une perspective ou fournir une table de recherche qui met en corrélation les API client et fournisseur. Pour plus d’informations sur la perspective du client, consultez le Guide du programmeur client UI Automation.

Remarque

Les clients UI Automation n’utilisent généralement pas de code managé et ne sont généralement pas implémentés en tant qu’application UWP (elles sont généralement des applications de bureau). UI Automation est basé sur une norme et non sur une implémentation ou une infrastructure spécifique. De nombreux clients UI Automation existants, notamment les produits technologiques d’assistance tels que les lecteurs d’écran, utilisent des interfaces COM (Component Object Model) pour interagir avec UI Automation, le système et les applications qui s’exécutent dans des fenêtres enfants. Pour plus d’informations sur les interfaces COM et sur la façon d’écrire un client UI Automation à l’aide de COM, consultez Principes de base d’UI Automation.

Détermination de l’état existant de la prise en charge d’UI Automation pour votre classe d’interface utilisateur personnalisée

Avant de tenter d’implémenter un homologue Automation pour un contrôle personnalisé, vous devez tester si la classe de base et son homologue Automation fournissent déjà la prise en charge de l’accessibilité ou de l’automatisation dont vous avez besoin. Dans de nombreux cas, la combinaison des implémentations FrameworkElementAutomationPeer , des homologues spécifiques et des modèles qu’ils implémentent peut fournir une expérience d’accessibilité de base mais satisfaisante. Si cela est vrai dépend du nombre de modifications apportées au modèle objet exposés à votre contrôle par rapport à sa classe de base. Cela dépend également si vos ajouts à la fonctionnalité de classe de base sont corrélés à de nouveaux éléments d’interface utilisateur dans le contrat de modèle ou à l’apparence visuelle du contrôle. Dans certains cas, vos modifications peuvent introduire de nouveaux aspects de l’expérience utilisateur qui nécessitent une prise en charge supplémentaire de l’accessibilité.

Même si l’utilisation de la classe homologue de base existante fournit la prise en charge de l’accessibilité de base, il est toujours recommandé de définir un homologue afin de pouvoir signaler des informations ClassName précises à UI Automation pour les scénarios de test automatisé. Cette considération est particulièrement importante si vous écrivez un contrôle destiné à une consommation tierce.

Classes d’homologue Automation

UWP s’appuie sur les techniques et conventions UI Automation existantes utilisées par des frameworks d’interface utilisateur de code managé précédents tels que Windows Forms, Windows Presentation Foundation (WPF) et Microsoft Silverlight. De nombreuses classes de contrôle et leur fonction et leur objectif ont également leur origine dans une infrastructure d’interface utilisateur précédente.

Par convention, les noms de classes homologues commencent par le nom de la classe de contrôle et se terminent par « AutomationPeer ». Par exemple, ButtonAutomationPeer est la classe homologue de la classe de contrôle Button .

Remarque

Dans le cadre de cette rubrique, nous traitons les propriétés liées à l’accessibilité comme étant plus importantes lorsque vous implémentez un homologue de contrôle. Toutefois, pour un concept plus général de prise en charge d’UI Automation, vous devez implémenter un homologue conformément aux recommandations décrites par le Guide du programmeur UI Automation et les principes de base d’UI Automation. Ces rubriques ne couvrent pas les API AutomationPeer spécifiques que vous utiliseriez pour fournir les informations dans l’infrastructure UWP pour UI Automation, mais elles décrivent les propriétés qui identifient votre classe ou fournissent d’autres informations ou interactions.

Pairs, modèles et types de contrôle

Un modèle de contrôle est une implémentation d’interface qui expose un aspect particulier des fonctionnalités d’un contrôle à un client UI Automation. Les clients UI Automation utilisent les propriétés et méthodes exposées via un modèle de contrôle pour récupérer des informations sur les fonctionnalités du contrôle ou pour manipuler le comportement du contrôle au moment de l’exécution.

Les modèles de contrôle permettent de catégoriser et d'exposer les fonctionnalités d'un contrôle, indépendamment du type de contrôle ou de l'apparence du contrôle. Par exemple, un contrôle qui présente une interface tabulaire utilise le modèle de contrôle Grid pour exposer le nombre de lignes et de colonnes dans la table, et pour permettre à un client UI Automation de récupérer des éléments de la table. Comme d’autres exemples, le client UI Automation peut utiliser le modèle de contrôle Invoke pour les contrôles qui peuvent être appelés, tels que les boutons et le modèle de contrôle Scroll pour les contrôles qui ont des barres de défilement, telles que des zones de liste, des affichages de liste ou des zones de liste modifiable. Chaque modèle de contrôle représente un type distinct de fonctionnalités, et les modèles de contrôle peuvent être combinés pour décrire l’ensemble complet de fonctionnalités prises en charge par un contrôle particulier.

Les modèles de contrôle sont liés à l’interface utilisateur en tant qu’interfaces liées aux objets COM. Dans COM, vous pouvez interroger un objet et lui demander quelles interfaces il prend en charge, puis vous servir de ces interfaces pour accéder aux fonctionnalités. Dans UI Automation, les clients UI Automation peuvent interroger un élément UI Automation pour savoir quels modèles de contrôle il prend en charge, puis interagir avec l’élément et son contrôle appairé via les propriétés, méthodes, événements et structures exposés par les modèles de contrôle pris en charge.

L’un des principaux objectifs d’un homologue Automation est de signaler à un client UI Automation qui contrôle les modèles d’interface utilisateur que l’élément d’interface utilisateur peut prendre en charge via son homologue. Pour ce faire, les fournisseurs UI Automation implémentent de nouveaux homologues qui modifient le comportement de la méthode GetPattern en remplaçant la méthode GetPatternCore. Les clients UI Automation effectuent des appels que le fournisseur UI Automation mappe à l’appel de GetPattern. Les clients UI Automation interrogent chaque modèle spécifique avec lequel ils souhaitent interagir. Si l’homologue prend en charge le modèle, il retourne une référence d’objet à elle-même ; sinon, elle retourne null. Si le retour n’est pas null, le client UI Automation s’attend à ce qu’il puisse appeler des API de l’interface de modèle en tant que client, afin d’interagir avec ce modèle de contrôle.

Un type de contrôle est un moyen de définir largement les fonctionnalités d’un contrôle que l’homologue représente. Il s’agit d’un concept différent d’un modèle de contrôle, car alors qu’un modèle informe UI Automation des informations qu’il peut obtenir ou quelles actions il peut effectuer via une interface particulière, le type de contrôle existe un niveau au-dessus de celui-ci. Chaque type de contrôle contient des conseils sur les aspects suivants d’UI Automation :

  • Modèles de contrôle UI Automation : un type de contrôle peut prendre en charge plusieurs modèles, chacun représentant une classification différente des informations ou des interactions. Chaque type de contrôle a un ensemble de modèles de contrôle que le contrôle doit prendre en charge, un ensemble facultatif et un ensemble que le contrôle ne doit pas prendre en charge.
  • Valeurs de propriété UI Automation : chaque type de contrôle a un ensemble de propriétés que le contrôle doit prendre en charge. Il s’agit des propriétés générales, comme décrit dans UI Automation Properties Overview, et non celles qui sont spécifiques au modèle.
  • Événements UI Automation : chaque type de contrôle a un ensemble d’événements que le contrôle doit prendre en charge. Là encore, ils sont généraux, et non spécifiques au modèle, comme décrit dans UI Automation Events Overview.
  • Structure d’arborescence UI Automation : chaque type de contrôle définit la façon dont le contrôle doit apparaître dans la structure de l’arborescence UI Automation.

Quelle que soit la façon dont les homologues d’automatisation pour l’infrastructure sont implémentés, la fonctionnalité cliente UI Automation n’est pas liée à UWP et, en fait, il est probable que les clients UI Automation existants tels que les technologies d’assistance utilisent d’autres modèles de programmation, tels que COM. Dans COM, les clients peuvent QueryInterface pour l’interface de modèle de contrôle COM qui implémente le modèle demandé ou l’infrastructure UI Automation générale pour les propriétés, les événements ou l’examen d’arborescence. Pour les modèles, l’infrastructure UI Automation marshale ce code d’interface dans le code UWP exécuté sur le fournisseur UI Automation de l’application et l’homologue approprié.

Lorsque vous implémentez des modèles de contrôle pour une infrastructure de code managé comme une application UWP à l’aide de C# ou microsoft Visual Basic, vous pouvez utiliser des interfaces .NET Framework pour représenter ces modèles au lieu d’utiliser la représentation d’interface COM. Par exemple, l’interface de modèle UI Automation pour une implémentation de fournisseur Microsoft .NET du modèle Invoke est IInvokeProvider.

Pour obtenir la liste des modèles de contrôle, des interfaces de fournisseur et leur objectif, consultez les modèles et interfaces de contrôle. Pour obtenir la liste des types de contrôle, consultez la vue d’ensemble des types de contrôle UI Automation.

Conseils pour implémenter des modèles de contrôle

Les modèles de contrôle et ce qu’ils sont destinés font partie d’une définition plus large de l’infrastructure UI Automation et ne s’appliquent pas simplement à la prise en charge de l’accessibilité pour une application UWP. Lorsque vous implémentez un modèle de contrôle, vous devez vous assurer que vous l’implémentez d’une manière qui correspond aux instructions décrites dans ces documents et également dans la spécification UI Automation. Si vous recherchez des conseils, vous pouvez généralement utiliser la documentation Microsoft et n’a pas besoin de faire référence à la spécification. Des conseils pour chaque modèle sont documentés ici : implémentation de modèles de contrôle UI Automation. Vous remarquerez que chaque rubrique de cette zone comporte une section « Directives et conventions d’implémentation » et une section « Membres requis ». Les instructions font généralement référence à des API spécifiques de l’interface de modèle de contrôle appropriée dans les interfaces de modèle de contrôle pour les fournisseurs de référence. Ces interfaces sont les interfaces natives/COM (et leurs API utilisent la syntaxe de style COM). Mais tout ce que vous voyez a un équivalent dans l’espace de noms Windows.UI.Xaml.Automation.Provider .

Si vous utilisez les homologues d’automatisation par défaut et que vous développez leur comportement, ces homologues ont déjà été écrits conformément aux instructions UI Automation. S’ils prennent en charge les modèles de contrôle, vous pouvez vous appuyer sur cette prise en charge conforme aux instructions de l’implémentation des modèles de contrôle UI Automation. Si un homologue de contrôle signale qu’il est représentatif d’un type de contrôle défini par UI Automation, les instructions documentées dans la prise en charge des types de contrôle UI Automation ont été suivies par cet homologue.

Néanmoins, vous devrez peut-être obtenir des conseils supplémentaires pour les modèles de contrôle ou les types de contrôle afin de suivre les recommandations UI Automation dans votre implémentation homologue. Cela serait particulièrement vrai si vous implémentez la prise en charge du modèle ou du type de contrôle qui n’existe pas encore en tant qu’implémentation par défaut dans un contrôle UWP. Par exemple, le modèle pour les annotations n’est implémenté dans aucun des contrôles XAML par défaut. Toutefois, vous pouvez avoir une application qui utilise des annotations de manière étendue et, par conséquent, vous souhaitez exposer cette fonctionnalité pour être accessible. Pour ce scénario, votre homologue doit implémenter IAnnotationProvider et doit probablement se signaler en tant que type de contrôle Document avec les propriétés appropriées pour indiquer que vos documents prennent en charge l’annotation.

Nous vous recommandons d’utiliser les conseils que vous voyez pour les modèles sous Implémentation des modèles de contrôle UI Automation ou des types de contrôle sous Prise en charge des types de contrôle UI Automation en tant qu’orientation et conseils généraux. Vous pouvez même essayer de suivre certains liens d’API pour des descriptions et des remarques quant à l’objectif des API. Toutefois, pour les spécificités de syntaxe nécessaires à la programmation d’applications UWP, recherchez l’API équivalente dans l’espace de noms Windows.UI.Xaml.Automation.Provider et utilisez ces pages de référence pour plus d’informations.

Classes homologues Automation intégrées

En général, les éléments implémentent une classe d’homologue Automation s’ils acceptent l’activité de l’interface utilisateur de l’utilisateur, ou s’ils contiennent des informations nécessaires aux utilisateurs de technologies d’assistance qui représentent l’interface utilisateur interactive ou significative des applications. Tous les éléments visuels UWP n’ont pas d’homologues d’automatisation. Exemples de classes qui implémentent des homologues Automation sont Button et TextBox. Les classes qui n’implémentent pas d’homologues d’automatisation sont des classes border et basées sur le panneau, telles que Grid et Canvas. Un panneau n’a pas d’homologue, car il fournit un comportement de disposition qui est visuel uniquement. Il n’existe aucun moyen pertinent pour l’utilisateur d’interagir avec un panneau. Les éléments enfants qu’un panneau contient sont signalés à des arborescences UI Automation en tant qu’éléments enfants du parent disponible suivant dans l’arborescence qui a une représentation d’homologue ou d’élément.

Limites de processus UI Automation et UWP

En règle générale, le code client UI Automation qui accède à une application UWP s’exécute hors processus. L’infrastructure d’infrastructure UI Automation permet d’obtenir des informations sur la limite de processus. Ce concept est expliqué plus en détail dans les notions de base d’UI Automation.

OnCreateAutomationPeer

Toutes les classes dérivées de UIElement contiennent la méthode virtuelle protégée OnCreateAutomationPeer. La séquence d’initialisation d’objet pour les homologues Automation appelle OnCreateAutomationPeer pour obtenir l’objet homologue Automation pour chaque contrôle et ainsi construire une arborescence UI Automation pour une utilisation au moment de l’exécution. Le code UI Automation peut utiliser l’homologue pour obtenir des informations sur les caractéristiques et les fonctionnalités d’un contrôle et pour simuler une utilisation interactive par le biais de ses modèles de contrôle. Un contrôle personnalisé qui prend en charge l’automatisation doit remplacer OnCreateAutomationPeer et retourner une instance d’une classe qui dérive d’AutomationPeer. Par exemple, si un contrôle personnalisé dérive de la classe ButtonBase, l’objet retourné par OnCreateAutomationPeer doit dériver de ButtonBaseAutomationPeer.

Si vous écrivez une classe de contrôle personnalisée et souhaitez également fournir un nouveau pair Automation, vous devez remplacer la méthode OnCreateAutomationPeer pour votre contrôle personnalisé afin qu’il retourne une nouvelle instance de votre homologue. Votre classe homologue doit dériver directement ou indirectement d’AutomationPeer.

Par exemple, le code suivant déclare que le contrôle NumericUpDown personnalisé doit utiliser l’homologue NumericUpDownPeer à des fins UI Automation.

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

Remarque

L’implémentation OnCreateAutomationPeer ne doit rien faire plus que d’initialiser une nouvelle instance de votre homologue Automation personnalisé, en passant le contrôle appelant en tant que propriétaire et en renvoyant cette instance. N’essayez pas une logique supplémentaire dans cette méthode. En particulier, toute logique susceptible d’entraîner la destruction de AutomationPeer au sein du même appel peut entraîner un comportement d’exécution inattendu.

Dans les implémentations classiques d’OnCreateAutomationPeer, le propriétaire est spécifié comme ceci ou Me, car le remplacement de méthode se trouve dans la même étendue que le reste de la définition de classe de contrôle.

La définition réelle de classe homologue peut être effectuée dans le même fichier de code que le contrôle ou dans un fichier de code distinct. Les définitions d’homologue existent toutes dans l’espace de noms Windows.UI.Xaml.Automation.Peer , qui est un espace de noms distinct des contrôles dont ils fournissent des homologues. Vous pouvez choisir de déclarer vos homologues dans des espaces de noms distincts aussi, tant que vous référencez les espaces de noms nécessaires pour l’appel de méthode OnCreateAutomationPeer .

Choix de la classe de base homologue appropriée

Assurez-vous que votre AutomationPeer est dérivé d’une classe de base qui vous donne la meilleure correspondance pour la logique homologue existante de la classe de contrôle à partir de laquelle vous dérivez. Dans le cas de l’exemple précédent, car NumericUpDown dérive de RangeBase, il existe une classe RangeBaseAutomationPeer disponible sur laquelle vous devez baser votre homologue. En utilisant la classe homologue correspondante la plus proche en parallèle de la façon dont vous dérivez le contrôle lui-même, vous pouvez éviter de remplacer au moins une partie de la fonctionnalité IRangeValueProvider , car la classe homologue de base l’implémente déjà.

La classe Control de base n’a pas de classe homologue correspondante. Si vous avez besoin d’une classe homologue pour correspondre à un contrôle personnalisé dérivé de Control, dérivez la classe d’homologue personnalisée de FrameworkElementAutomationPeer.

Si vous dérivez directement de ContentControl, cette classe n’a pas de comportement d’homologue Automation par défaut, car il n’existe aucune implémentation OnCreateAutomationPeer qui référence une classe homologue. Veillez donc à implémenter OnCreateAutomationPeer pour utiliser votre propre homologue ou à utiliser FrameworkElementAutomationPeer comme homologue si ce niveau de prise en charge de l’accessibilité convient à votre contrôle.

Remarque

Vous ne dérivez généralement pas d’AutomationPeer plutôt que de FrameworkElementAutomationPeer. Si vous avez dérivé directement d’AutomationPeer, vous devez dupliquer une grande partie de la prise en charge de l’accessibilité de base qui proviendrait sinon de FrameworkElementAutomationPeer.

Initialisation d’une classe homologue personnalisée

L’homologue Automation doit définir un constructeur de type sécurisé qui utilise une instance du contrôle propriétaire pour l’initialisation de base. Dans l’exemple suivant, l’implémentation transmet la valeur de propriétaire à la base RangeBaseAutomationPeer. En fin de compte, il s’agit de FrameworkElementAutomationPeer qui utilise réellement le propriétaire pour définir 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éthodes principales d’AutomationPeer

Pour des raisons d’infrastructure UWP, les méthodes substituables d’un homologue Automation font partie d’une paire de méthodes : la méthode d’accès public utilisée par le fournisseur UI Automation comme point de transfert pour les clients UI Automation et la méthode de personnalisation « Core » protégée qu’une classe UWP peut remplacer pour influencer le comportement. La paire de méthodes est câblée par défaut de telle sorte que l’appel à la méthode d’accès appelle toujours la méthode parallèle « Core » qui a l’implémentation du fournisseur, ou en tant que secours, appelle une implémentation par défaut à partir des classes de base.

Lors de l’implémentation d’un homologue pour un contrôle personnalisé, remplacez l’une des méthodes « Core » de la classe d’homologue Automation de base dans laquelle vous souhaitez exposer le comportement unique à votre contrôle personnalisé. Le code UI Automation obtient des informations sur votre contrôle en appelant des méthodes publiques de la classe homologue. Pour fournir des informations sur votre contrôle, remplacez chaque méthode par un nom qui se termine par « Core » lorsque votre implémentation et conception de contrôle crée des scénarios d’accessibilité ou d’autres scénarios UI Automation qui diffèrent de ce qui est pris en charge par la classe homologue Automation de base.

Au minimum, chaque fois que vous définissez une nouvelle classe homologue, implémentez la méthode GetClassNameCore , comme indiqué dans l’exemple suivant.

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

Remarque

Vous souhaiterez peut-être stocker les chaînes sous forme de constantes plutôt que directement dans le corps de la méthode, mais c’est à vous. Pour GetClassNameCore, vous n’aurez pas besoin de localiser cette chaîne. La propriété LocalizedControlType est utilisée chaque fois qu’une chaîne localisée est nécessaire par un client UI Automation, et non par ClassName.

GetAutomationControlType

Certaines technologies d’assistance utilisent la valeur GetAutomationControlType directement lors de la création de rapports des caractéristiques des éléments d’une arborescence UI Automation, comme informations supplémentaires au-delà du nom UI Automation. Si votre contrôle est sensiblement différent du contrôle à partir duquel vous dérivez et que vous souhaitez signaler un type de contrôle différent de ce qui est signalé par la classe homologue de base utilisée par le contrôle, vous devez implémenter un homologue et remplacer GetAutomationControlTypeCore dans votre implémentation homologue. Cela est particulièrement important si vous dérivez d’une classe de base généralisée telle que ItemsControl ou ContentControl, où l’homologue de base ne fournit pas d’informations précises sur le type de contrôle.

Votre implémentation de GetAutomationControlTypeCore décrit votre contrôle en retournant une valeur AutomationControlType. Bien que vous puissiez retourner AutomationControlType.Custom, vous devez renvoyer l’un des types de contrôle les plus spécifiques s’il décrit avec précision les principaux scénarios de votre contrôle. Voici un exemple.

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

Remarque

Sauf si vous spécifiez AutomationControlType.Custom, vous n’avez pas besoin d’implémenter GetLocalizedControlTypeCore pour fournir une valeur de propriété LocalizedControlType aux clients. L’infrastructure commune UI Automation fournit des chaînes traduites pour chaque valeur AutomationControlType possible autre que AutomationControlType.Custom.

GetPattern et GetPatternCore

L’implémentation d’un homologue de GetPatternCore retourne l’objet qui prend en charge le modèle demandé dans le paramètre d’entrée. Plus précisément, un client UI Automation appelle une méthode qui est transférée à la méthode GetPattern du fournisseur et spécifie une valeur d’énumération PatternInterface qui nomme le modèle demandé. Votre remplacement de GetPatternCore doit retourner l’objet qui implémente le modèle spécifié. Cet objet est l’homologue lui-même, car l’homologue doit implémenter l’interface de modèle correspondante chaque fois qu’il signale qu’il prend en charge un modèle. Si votre homologue n’a pas d’implémentation personnalisée d’un modèle, mais que vous savez que la base de l’homologue implémente le modèle, vous pouvez appeler l’implémentation du type de base de GetPatternCore à partir de votre GetPatternCore. GetPatternCore d’un homologue doit retourner null si un modèle n’est pas pris en charge par l’homologue. Toutefois, au lieu de retourner la valeur Null directement à partir de votre implémentation, vous devez généralement compter sur l’appel à l’implémentation de base pour retourner null pour tout modèle non pris en charge.

Lorsqu’un modèle est pris en charge, l’implémentation GetPatternCore peut renvoyer ceci ou Moi. L’attente est que le client UI Automation caste la valeur de retour GetPattern vers l’interface de modèle demandée chaque fois qu’il n’est pas null.

Si une classe homologue hérite d’un autre homologue, et que toutes les rapports de prise en charge et de modèle nécessaires sont déjà gérés par la classe de base, l’implémentation de GetPatternCore n’est pas nécessaire. Par exemple, si vous implémentez un contrôle de plage qui dérive de RangeBase et que votre homologue dérive de RangeBaseAutomationPeer, cet homologue se retourne pour PatternInterface.RangeValue et a des implémentations fonctionnelles de l’interface IRangeValueProvider qui prend en charge le modèle.

Bien qu’il ne s’agit pas du code littéral, cet exemple montre comment estimer l’implémentation de GetPatternCore déjà présente dans RangeBaseAutomationPeer.

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

Si vous implémentez un homologue dans lequel vous n’avez pas tout le support dont vous avez besoin à partir d’une classe d’homologue de base, ou si vous souhaitez modifier ou ajouter à l’ensemble de modèles hérités de base que votre homologue peut prendre en charge, vous devez remplacer GetPatternCore pour permettre aux clients UI Automation d’utiliser les modèles.

Pour obtenir la liste des modèles de fournisseur disponibles dans l’implémentation UWP de la prise en charge d’UI Automation, consultez Windows.UI.Xaml.Automation.Provider. Chaque modèle de ce type a une valeur correspondante de l’énumération PatternInterface, c’est-à-dire la façon dont les clients UI Automation demandent le modèle dans un appel GetPattern.

Un homologue peut signaler qu’il prend en charge plusieurs modèles. Dans ce cas, le remplacement doit inclure la logique de chemin d’accès de retour pour chaque valeur PatternInterface prise en charge et retourner l’homologue dans chaque cas correspondant. Il est prévu que l’appelant demande une seule interface à la fois et qu’il est à l’appelant de convertir l’interface attendue.

Voici un exemple de remplacement GetPatternCore pour un homologue personnalisé. Il signale la prise en charge de deux modèles, IRangeValueProvider et IToggleProvider. Le contrôle ici est un contrôle d’affichage multimédia qui peut s’afficher en mode plein écran (mode bascule) et qui a une barre de progression dans laquelle les utilisateurs peuvent sélectionner une position (le contrôle de plage). Ce code provient de l’exemple d’accessibilité XAML.

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

Modèles de transfert de sous-éléments

Une implémentation de méthode GetPatternCore peut également spécifier un sous-élément ou une partie en tant que fournisseur de modèles pour son hôte. Cet exemple montre comment ItemsControl transfère la gestion des modèles de défilement à l’homologue de son contrôle ScrollViewer interne. Pour spécifier un sous-élément pour la gestion des modèles, ce code obtient l’objet sous-élément, crée un homologue pour le sous-élément à l’aide de la méthode FrameworkElementAutomationPeer.CreatePeerForElement et retourne le nouvel homologue.

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

Autres méthodes principales

Votre contrôle peut avoir besoin de prendre en charge les équivalents clavier pour les scénarios principaux ; pour plus d’informations sur la raison pour laquelle cela peut être nécessaire, consultez l’accessibilité du clavier. L’implémentation de la prise en charge des clés fait nécessairement partie du code de contrôle et non du code homologue, car elle fait partie de la logique d’un contrôle, mais votre classe homologue doit remplacer les méthodes GetAcceleratorKeyCore et GetAccessKeyCore pour signaler aux clients UI Automation les clés utilisées. Considérez que les chaînes qui signalent des informations clés doivent être localisées et doivent donc provenir de ressources, et non de chaînes codées en dur.

Si vous fournissez un homologue pour une classe qui prend en charge une collection, il est préférable de dériver des classes fonctionnelles et des classes homologues qui ont déjà ce type de prise en charge de collection. Si vous ne pouvez pas le faire, les pairs pour les contrôles qui conservent des collections enfants peuvent avoir à remplacer la méthode d’homologue associée à la collection GetChildrenCore pour signaler correctement les relations parent-enfant à l’arborescence UI Automation.

Implémentez les méthodes IsContentElementCore et IsControlElementCore pour indiquer si votre contrôle contient du contenu de données ou remplit un rôle interactif dans l’interface utilisateur (ou les deux). Par défaut, les deux méthodes retournent true. Ces paramètres améliorent la facilité d’utilisation des technologies d’assistance telles que les lecteurs d’écran, qui peuvent utiliser ces méthodes pour filtrer l’arborescence d’automatisation. Si votre méthode GetPatternCore transfère la gestion des modèles à un homologue de sous-élément, la méthode IsControlElementCore de l’homologue de sous-élément peut retourner false pour masquer l’homologue de sous-élément de l’arborescence Automation.

Certains contrôles peuvent prendre en charge les scénarios d’étiquetage, où un composant d’étiquette de texte fournit des informations pour une partie non-texte, ou un contrôle est destiné à être dans une relation d’étiquetage connue avec un autre contrôle dans l’interface utilisateur. S’il est possible de fournir un comportement basé sur des classes utile, vous pouvez remplacer GetLabeledByCore pour fournir ce comportement.

GetBoundingRectangleCore et GetClickablePointCore sont principalement utilisés pour les scénarios de test automatisé. Si vous souhaitez prendre en charge les tests automatisés pour votre contrôle, vous pouvez remplacer ces méthodes. Cela peut être souhaité pour les contrôles de type plage, où vous ne pouvez pas suggérer un seul point, car l’utilisateur clique dans l’espace de coordonnées a un effet différent sur une plage. Par exemple, l’homologue d’automatisation ScrollBar par défaut remplace GetClickablePointCore pour renvoyer une valeur de point « pas un nombre ».

GetLiveSettingCore influence la valeur par défaut du contrôle pour la valeur LiveSetting pour UI Automation. Vous pouvez remplacer cela si vous souhaitez que votre contrôle retourne une valeur autre que AutomationLiveSetting.Off. Pour plus d’informations sur ce que Représente LiveSetting, consultez AutomationProperties.LiveSetting.

Vous pouvez remplacer GetOrientationCore si votre contrôle a une propriété d’orientation settable qui peut être mappée à AutomationOrientation. Les classes ScrollBarAutomationPeer et SliderAutomationPeer effectuent cette opération.

Implémentation de base dans FrameworkElementAutomationPeer

L’implémentation de base de FrameworkElementAutomationPeer fournit des informations UI Automation qui peuvent être interprétées à partir de différentes propriétés de disposition et de comportement définies au niveau de l’infrastructure.

Remarque

Les homologues UWP par défaut implémentent un comportement à l’aide du code natif interne qui implémente l’UWP, pas nécessairement à l’aide du code UWP réel. Vous ne pourrez pas voir le code ou la logique de l’implémentation via la réflexion CLR (Common Language Runtime) ou d’autres techniques. Vous ne verrez pas non plus de pages de référence distinctes pour les remplacements spécifiques aux sous-classes du comportement d’homologue de base. Par exemple, il peut y avoir un comportement supplémentaire pour GetNameCore d’un TextBoxAutomationPeer, qui ne sera pas décrit dans la page de référence AutomationPeer.GetNameCore et il n’existe aucune page de référence pour TextBoxAutomationPeer.GetNameCore. Il n’existe même pas de page de référence TextBoxAutomationPeer.GetNameCore . Au lieu de cela, lisez la rubrique de référence pour la classe homologue la plus immédiate et recherchez des notes d’implémentation dans la section Notes.

Pairs et AutomationProperties

Votre homologue Automation doit fournir les valeurs par défaut appropriées pour les informations relatives à l’accessibilité de votre contrôle. Notez que tout code d’application qui utilise le contrôle peut remplacer certains de ce comportement en incluant les valeurs de propriété jointe AutomationProperties sur les instances de contrôle. Les appelants peuvent effectuer cette opération soit pour les contrôles par défaut, soit pour les contrôles personnalisés. Par exemple, le code XAML suivant crée un bouton qui a deux propriétés UI Automation personnalisées : <Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>

Pour plus d’informations sur les propriétés jointes AutomationProperties, consultez les informations d’accessibilité de base.

Certaines des méthodes AutomationPeer existent en raison du contrat général de la façon dont les fournisseurs UI Automation sont censés signaler des informations, mais ces méthodes ne sont généralement pas implémentées dans les homologues de contrôle. Cela est dû au fait que ces informations sont censées être fournies par les valeurs AutomationProperties appliquées au code d’application qui utilise les contrôles dans une interface utilisateur spécifique. Par exemple, la plupart des applications définissent la relation d’étiquetage entre deux contrôles différents dans l’interface utilisateur en appliquant une valeur AutomationProperties.LabeledBy. Toutefois, LabeledByCore est implémenté dans certains homologues qui représentent des relations de données ou d’éléments dans un contrôle, comme l’utilisation d’un composant d’en-tête pour étiqueter un composant de champ de données, l’étiquetage d’éléments avec leurs conteneurs ou des scénarios similaires.

Implémentation de modèles

Examinons comment écrire un homologue pour un contrôle qui implémente un comportement de réduction de développement en implémentant l’interface de modèle de contrôle pour expand-collapse. L’homologue doit activer l’accessibilité pour le comportement expand-collapse en se retournant chaque fois que GetPattern est appelé avec une valeur de PatternInterface.ExpandCollapse. L’homologue doit ensuite hériter de l’interface du fournisseur pour ce modèle (IExpandCollapseProvider) et fournir des implémentations pour chacun des membres de cette interface de fournisseur. Dans ce cas, l’interface a trois membres à remplacer : Expand, Collapse, ExpandCollapseState.

Il est utile de planifier l’accessibilité dans la conception d’API de la classe elle-même. Chaque fois que vous avez un comportement potentiellement demandé à la suite d’interactions classiques avec un utilisateur qui travaille dans l’interface utilisateur ou via un modèle de fournisseur Automation, fournissez une méthode unique que la réponse de l’interface utilisateur ou le modèle Automation peut appeler. Par exemple, si votre contrôle comporte des parties de bouton qui ont des gestionnaires d’événements câblés qui peuvent développer ou réduire le contrôle et qui ont des équivalents clavier pour ces actions, ces gestionnaires d’événements appellent la même méthode que celle que vous appelez à partir du corps des implémentations Expand ou Collapse pour IExpandCollapseProvider dans l’homologue. L’utilisation d’une méthode logique commune peut également être un moyen utile de s’assurer que les états visuels de votre contrôle sont mis à jour pour afficher l’état logique de manière uniforme, quelle que soit la façon dont le comportement a été appelé.

Une implémentation classique est que les API du fournisseur appellent d’abord propriétaire pour l’accès à l’instance de contrôle au moment de l’exécution. Ensuite, les méthodes de comportement nécessaires peuvent être appelées sur cet objet.

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

Une autre implémentation est que le contrôle lui-même peut référencer son homologue. Il s’agit d’un modèle courant si vous déclenchez des événements d’automatisation à partir du contrôle, car la méthode RaiseAutomationEvent est une méthode homologue.

Événements UI Automation

Les événements UI Automation s’inscrivent dans les catégories suivantes.

Événement Description
Modification de propriété Se déclenche lorsqu’une propriété sur un élément UI Automation ou un modèle de contrôle change. Par exemple, si un client doit surveiller le contrôle de case à cocher d’une application, il peut s’inscrire pour écouter un événement de modification de propriété sur la propriété ToggleState. Lorsque le contrôle de case à cocher est activé ou désactivé, le fournisseur déclenche l’événement et le client peut agir si nécessaire.
Action d'élément Se déclenche lorsqu’une modification de l’interface utilisateur résulte d’une activité utilisateur ou programmatique ; par exemple, lorsqu’un bouton est cliqué ou appelé via le modèle Invoke .
Modification de la structure Se déclenche lorsque la structure de l’arborescence UI Automation change. La structure évolue quand de nouveaux éléments de l’interface utilisateur deviennent visibles, sont masqués ou sont supprimés sur le Bureau.
Changement global Se déclenche lorsque des actions d’intérêt global pour le client se produisent, par exemple lorsque le focus passe d’un élément à un autre ou lorsqu’une fenêtre enfant se ferme. Certains événements ne signifient pas nécessairement que l'état de l'interface utilisateur a changé. Par exemple, si l’utilisateur accède à un champ d’entrée de texte, puis clique sur un bouton pour mettre à jour le champ, un événement TextChanged se déclenche même si l’utilisateur n’a pas réellement modifié le texte. Pendant le traitement d'un événement, une application cliente peut être amenée à vérifier ce qui a réellement changé avant d'agir.

Identificateurs AutomationEvents

Les événements UI Automation sont identifiés par les valeurs AutomationEvents. Les valeurs de l’énumération identifient de manière unique le type d’événement.

Déclenchement d'événements

Les clients UI Automation peuvent s’abonner aux événements Automation. Dans le modèle d’homologue Automation, les homologues pour les contrôles personnalisés doivent signaler des modifications à l’état de contrôle pertinents pour l’accessibilité en appelant la méthode RaiseAutomationEvent. De même, lorsqu’une valeur de propriété UI Automation clé change, les homologues de contrôle personnalisés doivent appeler la méthode RaisePropertyChangedEvent.

L’exemple de code suivant montre comment obtenir l’objet homologue à partir du code de définition de contrôle et appeler une méthode pour déclencher un événement à partir de cet homologue. En guise d’optimisation, le code détermine s’il existe des écouteurs pour ce type d’événement. Déclencher l’événement et créer l’objet homologue uniquement lorsqu’il existe des écouteurs évite une surcharge inutile et aide le contrôle à rester réactif.

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

Navigation d’homologue

Après avoir localisé un homologue Automation, un client UI Automation peut naviguer dans la structure homologue d’une application en appelant les méthodes GetChildren et GetParent de l’objet homologue. La navigation entre les éléments d’interface utilisateur au sein d’un contrôle est prise en charge par l’implémentation de l’homologue de la méthode GetChildrenCore. Le système UI Automation appelle cette méthode pour créer une arborescence de sous-éléments contenus dans un contrôle ; par exemple, les éléments de liste dans une zone de liste. La méthode GetChildrenCore par défaut dans FrameworkElementAutomationPeer traverse l’arborescence visuelle des éléments pour générer l’arborescence des homologues d’automatisation. Les contrôles personnalisés peuvent remplacer cette méthode pour exposer une représentation différente des éléments enfants aux clients Automation, en retournant les homologues d’automatisation des éléments qui transmettent des informations ou autorisent l’interaction utilisateur.

Prise en charge de l’automatisation native pour les modèles de texte

Certains homologues d’automatisation d’application UWP par défaut prennent en charge le modèle de contrôle pour le modèle de texte (PatternInterface.Text). Mais ils fournissent cette prise en charge par le biais de méthodes natives, et les homologues impliqués ne notent pas l’interface ITextProvider dans l’héritage (géré). Toutefois, si un client UI Automation géré ou non géré interroge l’homologue pour les modèles, il signale la prise en charge du modèle de texte et fournit un comportement pour les parties du modèle lorsque les API clientes sont appelées.

Si vous envisagez de dériver de l’un des contrôles de texte de l’application UWP et de créer un homologue personnalisé qui dérive d’un des homologues liés au texte, consultez les sections Remarques de l’homologue pour en savoir plus sur toute prise en charge au niveau natif des modèles. Vous pouvez accéder au comportement de base natif dans votre homologue personnalisé si vous appelez l’implémentation de base à partir de vos implémentations d’interface de fournisseur managé, mais il est difficile de modifier ce que fait l’implémentation de base, car les interfaces natives sur l’homologue et son contrôle propriétaire ne sont pas exposées. En règle générale, vous devez utiliser les implémentations de base telles quelles (base d’appels uniquement) ou remplacer complètement les fonctionnalités par votre propre code managé et n’appelez pas l’implémentation de base. Ce dernier est un scénario avancé, vous aurez besoin d’une bonne connaissance de l’infrastructure de services de texte utilisée par votre contrôle pour prendre en charge les exigences d’accessibilité lors de l’utilisation de ce framework.

AutomationProperties.AccessibilityView

En plus de fournir un homologue personnalisé, vous pouvez également ajuster la représentation d’arborescence pour n’importe quelle instance de contrôle, en définissant AutomationProperties.AccessibilityView en XAML. Cela n’est pas implémenté dans le cadre d’une classe homologue, mais nous allons le mentionner ici, car il est allemand à la prise en charge globale de l’accessibilité pour les contrôles personnalisés ou pour les modèles que vous personnalisez.

Le scénario principal d’utilisation d’AutomationProperties.AccessibilityView consiste à omettre délibérément certains contrôles dans un modèle à partir des vues UI Automation, car ils ne contribuent pas de manière significative à l’affichage d’accessibilité de l’ensemble du contrôle. Pour éviter cela, définissez AutomationProperties.AccessibilityView sur « Raw ».

Levée d’exceptions à partir d’homologues Automation

Les API que vous implémentez pour votre support d’homologue Automation sont autorisées à lever des exceptions. Il est attendu que tous les clients UI Automation qui écoutent sont suffisamment robustes pour continuer une fois la plupart des exceptions levées. Dans toutes les probabilités que l’écouteur examine une arborescence d’automatisation complète qui inclut des applications autres que vos propres, et qu’il s’agit d’une conception client inacceptable pour réduire l’ensemble du client simplement parce qu’une zone de l’arborescence a levé une exception basée sur un homologue lorsque le client a appelé ses API.

Pour les paramètres passés à votre homologue, il est acceptable de valider l’entrée, et par exemple de lever ArgumentNullException s’il a été passé null et qu’il n’est pas une valeur valide pour votre implémentation. Toutefois, s’il existe des opérations suivantes effectuées par votre homologue, n’oubliez pas que les interactions de l’homologue avec le contrôle d’hébergement ont quelque chose de caractère asynchrone pour eux. Tout ce qu’un homologue ne bloque pas nécessairement le thread d’interface utilisateur dans le contrôle (et il ne devrait probablement pas le faire). Vous pourriez donc avoir des situations où un objet était disponible ou avait certaines propriétés lors de la création de l’homologue ou lorsqu’une méthode d’homologue Automation a été appelée pour la première fois, mais en attendant, l’état du contrôle a changé. Dans ce cas, il existe deux exceptions dédiées qu’un fournisseur peut lever :

Au-delà de cela, les pairs doivent être relativement prudents en ce qui concerne les exceptions qu’ils lèvent de leur support homologue. La plupart des clients ne pourront pas gérer les exceptions des pairs et les transformer en choix actionnables que leurs utilisateurs peuvent effectuer lors de l’interaction avec le client. Par conséquent, parfois, une absence d’opération et l’interception d’exceptions sans rethrowing dans vos implémentations d’homologues est une meilleure stratégie que de lever des exceptions chaque fois que l’homologue tente de faire ne fonctionne pas. Considérez également que la plupart des clients UI Automation ne sont pas écrits dans du code managé. La plupart sont écrits dans COM et recherchent simplement des S_OK dans un HRESULT chaque fois qu’ils appellent une méthode cliente UI Automation qui finit par accéder à votre homologue.