UI Automation d'un contrôle personnalisé WPF
UI Automation fournit une interface unique et généralisée que les clients Automation peuvent utiliser pour examiner ou exploiter les interfaces utilisateur de diverses plateformes et infrastructures. UI Automation permet à la fois le code d’assurance qualité (test) et les applications d’accessibilité, telles que les lecteurs d’écran, d’examiner les éléments de l’interface utilisateur et de simuler l’interaction utilisateur avec eux à partir d’autres codes. Pour plus d’informations sur UI Automation sur toutes les plateformes, consultez Accessibilité.
Cette rubrique explique comment implémenter un fournisseur UI Automation côté serveur pour un contrôle personnalisé qui s’exécute dans une application WPF. WPF prend en charge UI Automation par le biais d’une arborescence d’objets d’automatisation d’homologue qui parallèle à l’arborescence des éléments d’interface utilisateur. Le code de test et les applications qui fournissent des fonctionnalités d’accessibilité peuvent utiliser des objets homologues Automation directement (pour le code in-process) ou via l’interface généralisée fournie par UI Automation.
Classes homologues Automation
Les contrôles WPF prennent en charge UI Automation via une arborescence de classes homologues qui dérivent de AutomationPeer. 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 Button classe de contrôle. Les classes homologues sont à peu près équivalentes aux types de contrôle UI Automation, mais sont spécifiques aux éléments WPF. Le code Automation qui accède aux applications WPF via l’interface UI Automation n’utilise pas directement des homologues Automation, mais le code automation dans le même espace de processus peut utiliser directement des homologues Automation.
Classes homologues Automation intégrées
Des éléments implémentent une classe homologue Automation s’ils acceptent l’activité de l’utilisateur dans l’interface, ou s’ils contiennent les informations dont ont besoin les utilisateurs d’applications de lecteur d’écran. Tous les éléments visuels WPF n’ont pas d’homologues Automation. Exemples de classes qui implémentent des homologues d’automatisation sont Button, TextBoxet Label. Des exemples de classes qui n’implémentent pas d’homologues d’automatisation sont des classes qui dérivent Decorator, par Borderexemple, et des classes basées sur Panel, telles que Grid et Canvas.
La classe de base Control n’a pas de classe homologue correspondante. Si vous avez besoin d’une classe homologue pour correspondre à un contrôle personnalisé qui dérive de Control, vous devez dériver la classe d’homologue personnalisée à partir de FrameworkElementAutomationPeer.
Considérations relatives à la sécurité des homologues dérivés
Les homologues Automation doivent s’exécuter dans un environnement de confiance partielle. Le code dans l’assembly UIAutomationClient n’est pas configuré pour s’exécuter dans un environnement de confiance partielle et le code homologue Automation ne doit pas référencer cet assembly. Au lieu de cela, vous devez utiliser les classes de l’assembly UIAutomationTypes. Par exemple, vous devez utiliser la AutomationElementIdentifiers classe de l’assembly UIAutomationTypes, qui correspond à la AutomationElement classe dans l’assembly UIAutomationClient. La démarche la plus sûre consiste à référencer l’assembly UIAutomationTypes dans le code homologue Automation.
Navigation homologue
Après avoir localisé un homologue Automation, le code in-process peut naviguer dans l’arborescence homologue en appelant les méthodes et GetParent les méthodes de GetChildren l’objet. La navigation entre les éléments WPF au sein d’un contrôle est prise en charge par l’implémentation de la GetChildrenCore méthode par l’homologue. Le système UI Automation appelle cette méthode pour générer une arborescence de sous-éléments contenus dans un contrôle ; par exemple, des éléments de liste dans une zone de liste. La méthode par défaut UIElementAutomationPeer.GetChildrenCore traverse l’arborescence visuelle des éléments pour générer l’arborescence des homologues d’automatisation. Les contrôles personnalisés contournent cette méthode pour exposer les éléments enfants aux clients Automation, en retournant les homologues Automation des éléments qui acheminent des informations ou qui permettent une interaction avec l’utilisateur.
Personnalisations dans un homologue dérivé
Toutes les classes qui dérivent et UIElementContentElement contiennent la méthode OnCreateAutomationPeervirtuelle protégée . Appels OnCreateAutomationPeer WPF pour obtenir l’objet homologue Automation pour chaque contrôle. Le code 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. Un contrôle personnalisé qui prend en charge l’automatisation doit remplacer OnCreateAutomationPeer et retourner une instance d’une classe qui dérive de AutomationPeer. Par exemple, si un contrôle personnalisé dérive de la ButtonBase classe, l’objet retourné par OnCreateAutomationPeer doit dériver de ButtonBaseAutomationPeer.
Lorsque vous implémentez un contrôle personnalisé, vous devez substituer les méthodes « Core » à partir de la classe homologue Automation de base qui décrivent le comportement unique et spécifique à votre contrôle personnalisé.
Substituer la méthode OnCreateAutomationPeer
Remplacez la OnCreateAutomationPeer méthode de votre contrôle personnalisé afin qu’il retourne votre objet fournisseur, qui doit dériver directement ou indirectement de AutomationPeer.
Substituer la méthode GetPattern
Les homologues Automation simplifient certains aspects de l’implémentation des fournisseurs UI Automation côté serveur, mais les homologues d’automatisation de contrôle personnalisé doivent toujours gérer les interfaces de modèle. Comme les fournisseurs non WPF, les homologues prennent en charge les modèles de contrôle en fournissant des implémentations d’interfaces dans l’espace System.Windows.Automation.Provider de noms, telles que IInvokeProvider. Les interfaces de modèle de contrôle peuvent être implémentées par l’homologue lui-même ou par un autre objet. L’implémentation de l’homologue retourne GetPattern l’objet qui prend en charge le modèle spécifié. Le code UI Automation appelle la GetPattern méthode et spécifie une PatternInterface valeur d’énumération. Votre remplacement GetPattern doit retourner l’objet qui implémente le modèle spécifié. Si votre contrôle n’a pas d’implémentation personnalisée d’un modèle, vous pouvez appeler l’implémentation du type de base pour GetPattern récupérer son implémentation ou sa valeur Null si le modèle n’est pas pris en charge pour ce type de contrôle. Par exemple, un contrôle NumericUpDown personnalisé peut être défini sur une valeur dans une plage, de sorte que son homologue UI Automation implémente l’interface IRangeValueProvider . L’exemple suivant montre comment la méthode de l’homologue GetPattern est substituée pour répondre à une PatternInterface.RangeValue valeur.
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPattern(patternInterface);
}
Public Overrides Function GetPattern(ByVal patternInterface As PatternInterface) As Object
If patternInterface = PatternInterface.RangeValue Then
Return Me
End If
Return MyBase.GetPattern(patternInterface)
End Function
Une GetPattern méthode peut également spécifier un sous-élément en tant que fournisseur de modèles. Le code suivant montre comment ItemsControl transfère la gestion des modèles de défilement vers l’homologue de son contrôle interne ScrollViewer .
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Scroll)
{
ItemsControl owner = (ItemsControl) base.Owner;
// ScrollHost is internal to the ItemsControl class
if (owner.ScrollHost != null)
{
AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
if ((peer != null) && (peer is IScrollProvider))
{
peer.EventsSource = this;
return (IScrollProvider) peer;
}
}
}
return base.GetPattern(patternInterface);
}
Public Class Class1
Public Overrides Function GetPattern(ByVal patternInterface__1 As PatternInterface) As Object
If patternInterface1 = PatternInterface.Scroll Then
Dim owner As ItemsControl = DirectCast(MyBase.Owner, ItemsControl)
' ScrollHost is internal to the ItemsControl class
If owner.ScrollHost IsNot Nothing Then
Dim peer As AutomationPeer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost)
If (peer IsNot Nothing) AndAlso (TypeOf peer Is IScrollProvider) Then
peer.EventsSource = Me
Return DirectCast(peer, IScrollProvider)
End If
End If
End If
Return MyBase.GetPattern(patternInterface1)
End Function
End Class
Pour spécifier un sous-élément pour la gestion des modèles, ce code obtient l’objet de sous-élément, crée un homologue à l’aide de la CreatePeerForElement méthode, définit la EventsSource propriété du nouvel homologue sur l’homologue actuel et retourne le nouvel homologue. La définition EventsSource d’un sous-élément empêche l’affichage du sous-élément dans l’arborescence d’homologues Automation et désigne tous les événements déclenchés par le sous-élément comme provenant du contrôle spécifié dans EventsSource. Le ScrollViewer contrôle n’apparaît pas dans l’arborescence Automation et les événements de défilement générés semblent provenir de l’objet ItemsControl .
Substituer les méthodes « Core »
Le code 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, substituez chaque méthode dont le nom se termine par « Core » lorsque l’implémentation de votre contrôle diffère de celle fournie par la classe homologue Automation de base. Au minimum, votre contrôle doit implémenter les méthodes et GetAutomationControlTypeCore les GetClassNameCore méthodes, comme illustré dans l’exemple suivant.
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
Protected Overrides Function GetClassNameCore() As String
Return "NumericUpDown"
End Function
Protected Overrides Function GetAutomationControlTypeCore() As AutomationControlType
Return AutomationControlType.Spinner
End Function
Votre implémentation de GetAutomationControlTypeCore décrit votre contrôle en retournant une ControlType valeur. Bien que vous puissiez retourner, vous devez renvoyer ControlType.Customl’un des types de contrôle les plus spécifiques s’il décrit avec précision votre contrôle. Une valeur de retour nécessite ControlType.Custom un travail supplémentaire pour que le fournisseur implémente UI Automation et les produits clients UI Automation ne peuvent pas anticiper la structure de contrôle, l’interaction clavier et les modèles de contrôle possibles.
Implémentez les méthodes et IsControlElementCore les IsContentElementCore méthodes pour indiquer si votre contrôle contient du contenu des données ou remplit un rôle interactif dans l’interface utilisateur (ou les deux). Par défaut, ces deux méthodes retournent true
. Ces paramètres facilitent l’utilisation des outils Automatisation, comme les lecteurs d’écran, qui peuvent utiliser ces méthodes pour filtrer l’arborescence Automation. Si votre GetPattern méthode transfère la gestion des modèles à un homologue de sous-élément, la méthode de l’homologue de IsControlElementCore sous-élément peut retourner false pour masquer l’homologue de sous-élément de l’arborescence Automation. Par exemple, le défilement dans un ListBox est géré par un ScrollViewerhomologue Automation pour PatternInterface.Scroll lequel il est retourné par la GetPattern méthode du ScrollViewerAutomationPeer fichier associé au ListBoxAutomationPeer. Par conséquent, la IsControlElementCore méthode des ScrollViewerAutomationPeer retours false
, afin que la ScrollViewerAutomationPeer valeur ne s’affiche pas dans l’arborescence d’automatisation.
Votre homologue Automation doit fournir des valeurs par défaut appropriées pour votre contrôle. Notez que LE code XAML qui référence votre contrôle peut remplacer vos implémentations homologues de méthodes principales en incluant AutomationProperties des attributs. 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."/>
Implémenter des fournisseurs de modèles
Les interfaces implémentées par un fournisseur personnalisé sont explicitement déclarées si l’élément propriétaire dérive directement de Control. Par exemple, le code suivant déclare un homologue pour un Control qui implémente une valeur de plage.
public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }
Public Class RangePeer1
Inherits FrameworkElementAutomationPeer
Implements IRangeValueProvider
End Class
Si le contrôle propriétaire dérive d’un type spécifique de contrôle tel que RangeBase, l’homologue peut être dérivé d’une classe homologue dérivée équivalente. Dans ce cas, l’homologue dériverait de RangeBaseAutomationPeer, qui fournit une implémentation de base de IRangeValueProvider. Le code suivant illustre la déclaration de ce type d’homologue.
public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
Inherits RangeBaseAutomationPeer
End Class
Pour obtenir un exemple d’implémentation, consultez le code source C# ou Visual Basic qui implémente et consomme un contrôle personnalisé NumericUpDown.
Déclencher des événements
Les clients Automation peuvent s’abonner à des événements Automation. Les contrôles personnalisés doivent signaler les modifications apportées à l’état de contrôle en appelant la RaiseAutomationEvent méthode. De même, lorsqu’une valeur de propriété change, appelez la RaisePropertyChangedEvent méthode. Le code suivant montre comment obtenir l’objet homologue à partir du code de contrôle et appeler une méthode pour déclencher un événement. À des fins d’optimisation, le code détermine s’il existe des écouteurs pour ce type d’événement. Déclencher l’événement uniquement lorsqu’il y a des écouteurs évite les surcharges inutiles et permet au contrôle de rester réactif.
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}
If AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged) Then
Dim peer As NumericUpDownAutomationPeer = TryCast(UIElementAutomationPeer.FromElement(nudCtrl), NumericUpDownAutomationPeer)
If peer IsNot Nothing Then
peer.RaisePropertyChangedEvent(RangeValuePatternIdentifiers.ValueProperty, CDbl(oldValue), CDbl(newValue))
End If
End If
Voir aussi
.NET Desktop feedback