UI-automatisering van een aangepast WPF-besturingselement
UI Automation biedt één gegeneraliseerde interface die automatiseringsclients kunnen gebruiken om de gebruikersinterfaces van verschillende platforms en frameworks te onderzoeken of te gebruiken. Ui Automation maakt het mogelijk om zowel kwaliteitscontrole (testcode) als toegankelijkheidstoepassingen, zoals schermlezers, gebruikersinterface-elementen te onderzoeken en gebruikersinteractie met hen te simuleren vanuit andere code. Zie Toegankelijkheid voor informatie over UI-automatisering op alle platforms.
In dit onderwerp wordt beschreven hoe u een UI-Automatiseringsprovider aan de serverzijde implementeert voor een aangepaste controle die draait in een WPF-toepassing. WPF ondersteunt UI Automation via een boomstructuur van peerautomatiseringsobjecten die de structuur van elementen van de gebruikersinterface parallelleert. Test code en toepassingen die toegankelijkheidsfuncties bieden, kunnen automatiseringspeeringsobjecten rechtstreeks (voor in-process code) of via de gegeneraliseerde interface van UI Automation gebruiken.
Automation-peerklassen
WPF-besturingselementen ondersteunen UI Automation via een structuur van peerklassen die zijn afgeleid van AutomationPeer. Standaard beginnen peerklassenamen met de naam van de besturingsklasse en eindigen ze met AutomationPeer. ButtonAutomationPeer is bijvoorbeeld de peerklasse voor de Button besturingsklasse. De peerklassen zijn ongeveer gelijk aan UI Automation-besturingstypen, maar zijn specifiek voor WPF-elementen. Automatiseringscode die toegang heeft tot WPF-toepassingen via de UI Automation-interface maakt niet rechtstreeks gebruik van automatiseringspeers, maar automatiseringscode binnen dezelfde procesruimte kan automatiseringspeers wel rechtstreeks gebruiken.
Ingebouwde Automation-peerklassen
Elementen implementeren een automatiseringspeeringsklasse als ze interfaceactiviteit van de gebruiker accepteren of als ze informatie bevatten die nodig is voor gebruikers van schermlezertoepassingen. Niet alle WPF-visuele componenten hebben automatiseringspartners. Voorbeelden van klassen die automatiseringspeeringen implementeren, zijn Button, TextBoxen Label. Voorbeelden van klassen die geen automatiseringspeeringen implementeren, zijn klassen die zijn afgeleid van Decorator, zoals Border, en klassen op basis van Panel, zoals Grid en Canvas.
De basisklasse Control heeft geen bijbehorende peerklasse. Als u een peerklasse nodig hebt om te corresponderen met een aangepast besturingselement dat is afgeleid van Control, moet u de aangepaste peerklasse afleiden van FrameworkElementAutomationPeer.
Beveiligingsoverwegingen voor afgeleide peers
Automatiseringspeeringen moeten worden uitgevoerd in een gedeeltelijke vertrouwensomgeving. Code in de UIAutomationClient-assembly is niet ingesteld om te draaien in een omgeving met beperkte rechten, en automatiseringscode van peers mag niet naar die assembly verwijzen. In plaats daarvan moet u de klassen in de assembly UIAutomationTypes gebruiken. U moet bijvoorbeeld de AutomationElementIdentifiers klasse van de assembly UIAutomationTypes gebruiken, die overeenkomt met de klasse AutomationElement in de assembly UIAutomationClient. Het is veilig om te verwijzen naar de assembly UIAutomationTypes in automation-peercode.
Peernavigatie
Nadat u een automatiseringspeer hebt gevonden, kan in-procescode door de peerboom navigeren door de GetChildren- en GetParent-methoden van het object aan te roepen. Navigatie tussen WPF-elementen binnen een besturingselement wordt ondersteund door de implementatie van de GetChildrenCore-methode door de tegenhanger. Het UI Automation-systeem roept deze methode aan om een structuur van subelementen in een besturingsbeheer op te bouwen; bijvoorbeeld lijstitems in een keuzelijst. De standaardmethode UIElementAutomationPeer.GetChildrenCore doorkruist de visuele structuur van elementen om de structuur van automatiseringspeers op te bouwen. Aangepaste besturingselementen overschrijven deze methode om onderliggende elementen beschikbaar te maken voor automatiseringsclients, waarbij de automatiseringspeeringen van elementen worden geretourneerd die informatie overbrengen of gebruikersinteractie toestaan.
Aanpassingen in een afgeleide peer
Alle klassen die zijn afgeleid van UIElement en ContentElement bevatten de beveiligde virtuele methode OnCreateAutomationPeer. WPF roept OnCreateAutomationPeer aan om het automatiserings-peerobject voor elk bedieningselement op te halen. Automation-code kan de peer gebruiken om informatie op te halen over de kenmerken en functies van een besturingselement en om interactief gebruik te simuleren. Een aangepast besturingselement dat automatisering ondersteunt, moet OnCreateAutomationPeer overschrijven en een exemplaar retourneren van een klasse die is afgeleid van AutomationPeer. Als een aangepast besturingselement bijvoorbeeld is afgeleid van de ButtonBase klasse, moet het object dat door OnCreateAutomationPeer wordt geretourneerd, worden afgeleid van ButtonBaseAutomationPeer.
Wanneer u een aangepast besturingselement implementeert, moet u de core-methoden overschrijven uit de peerklasse basisautomatisering die het gedrag uniek en specifiek voor uw aangepaste besturingselement beschrijven.
OnCreateAutomationPeer overschrijven
Overschrijf de OnCreateAutomationPeer methode voor uw aangepaste besturingselement zodat het uw providerobject retourneert, dat rechtstreeks of indirect moet worden afgeleid van AutomationPeer.
GetPattern overschrijven
Automatiseringspeeringen vereenvoudigen enkele implementatieaspecten van UI Automation-providers aan de serverzijde, maar aangepaste automatiseringspeeringspeers moeten nog steeds patrooninterfaces verwerken. Net als niet-WPF-providers ondersteunen peers controlepatronen door implementaties van interfaces in de System.Windows.Automation.Provider naamruimte te bieden, zoals IInvokeProvider. De besturingspatrooninterfaces kunnen worden geïmplementeerd door de peer zelf of door een ander object. De implementatie van de peer van GetPattern retourneert het object dat het opgegeven patroon ondersteunt. Ui Automation-code roept de GetPattern-methode aan en geeft een PatternInterface opsommingswaarde op. Uw overschrijving van GetPattern moet het object teruggeven dat het opgegeven patroon implementeert. Als uw controle-element geen aangepaste implementatie van een patroon heeft, kunt u de implementatie van het basistype van GetPattern aanroepen om de implementatie of 'null' (geen) op te halen als het patroon niet wordt ondersteund voor dit type controle-element. Het aangepaste NumericUpDown-besturingselement kan bijvoorbeeld worden ingesteld op een waarde binnen een bereik, zodat de UI Automation-peer de IRangeValueProvider-interface zal implementeren. In het volgende voorbeeld laten we zien hoe de methode GetPattern van de peer wordt overschreven om te reageren op een waarde PatternInterface.RangeValue.
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
Een GetPattern-methode kan ook een subelement opgeven als patroonprovider. De volgende code laat zien hoe ItemsControl de verwerking van scrollpatronen overdraagt naar de peer van het interne ScrollViewer-besturingselement.
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
Als u een subelement voor patroonafhandeling wilt opgeven, wordt met deze code het subelementobject opgehaald, wordt een peer gemaakt met behulp van de methode CreatePeerForElement, wordt de eigenschap EventsSource van de nieuwe peer ingesteld op de huidige peer en wordt de nieuwe peer geretourneerd. Als u EventsSource instelt op een subelement, voorkomt u dat het subelement wordt weergegeven in de automatiseringspeerstructuur en worden alle gebeurtenissen die door het subelement worden gegenereerd beschouwd als afkomstig van de controle die is opgegeven in EventsSource. De ScrollViewer-besturing verschijnt niet in de automatiseringsstructuur en de scrollgebeurtenissen die het genereert, lijken afkomstig te zijn van het ItemsControl-object.
Core-methoden overschrijven
Automatiseringscode haalt informatie over uw controle op door openbare methoden van de peerklasse aan te roepen. Als u informatie over uw controle wilt opgeven, overschrijft u elke methode waarvan de naam eindigt op Core wanneer uw controle-implementatie verschilt van die van de basis-automatiseringspeeringsklasse. Ten minste moet uw besturingselement de methoden GetClassNameCore en GetAutomationControlTypeCore implementeren, zoals wordt weergegeven in het volgende voorbeeld.
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
Uw implementatie van GetAutomationControlTypeCore beschrijft uw controle door een ControlType waarde te retourneren. Hoewel u ControlType.Customkunt retourneren, moet u een van de meer specifieke besturingstypen retourneren als dit uw besturing nauwkeurig beschrijft. Een retourwaarde van ControlType.Custom vereist extra werk voor de provider om UI Automation te implementeren en UI Automation-clientproducten kunnen niet anticiperen op de besturingsstructuur, toetsenbordinteractie en mogelijke besturingspatronen.
Implementeer de methoden IsContentElementCore en IsControlElementCore om aan te geven of uw besturingselement gegevensinhoud bevat of voldoet aan een interactieve rol in de gebruikersinterface (of beide). Standaard retourneren beide methoden true
. Deze instellingen verbeteren de bruikbaarheid van automatiseringshulpprogramma's zoals schermlezers, die deze methoden kunnen gebruiken om de automatiseringsstructuur te filteren. Als uw GetPattern methode patroonafhandeling overdraagt naar een subelementpeer, kan de IsControlElementCore methode van de subelementpeer onwaar retourneren om de subelementpeer uit de automatiseringsstructuur te verbergen. Schuiven in een ListBox wordt bijvoorbeeld afgehandeld door een ScrollViewer, en de automation peer voor PatternInterface.Scroll wordt geretourneerd door de GetPattern-methode van de ScrollViewerAutomationPeer die is gekoppeld aan de ListBoxAutomationPeer. Daarom retourneert de IsControlElementCore-methode van de ScrollViewerAutomationPeerfalse
, zodat de ScrollViewerAutomationPeer niet verschijnt in de automatiseringsstructuur.
Uw automatiseringspartner zou de juiste standaardwaarden voor uw besturingselement moeten opgeven. Houd er rekening mee dat XAML die verwijst naar uw controle uw peer-implementaties van kernmethoden kan overschrijven door AutomationProperties kenmerken op te slaan. Met de volgende XAML wordt bijvoorbeeld een knop gemaakt met twee aangepaste UI Automation-eigenschappen.
<Button AutomationProperties.Name="Special"
AutomationProperties.HelpText="This is a special button."/>
Patroonproviders implementeren
De interfaces die door een aangepaste provider worden geïmplementeerd, worden expliciet gedeclareerd als het element dat eigenaar is, rechtstreeks is afgeleid van Control. De volgende code declareert bijvoorbeeld een peer voor een Control waarmee een bereikwaarde wordt geïmplementeerd.
public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }
Public Class RangePeer1
Inherits FrameworkElementAutomationPeer
Implements IRangeValueProvider
End Class
Als het eigendomscontrole-element is afgeleid van een specifiek type controle-element, zoals RangeBase, kan de peer zijn afgeleid van een equivalente afgeleide peerklasse. In dit geval zou de peer zijn afgeleid van RangeBaseAutomationPeer, die een basisuitvoering van IRangeValueProviderlevert. De volgende code laat zien hoe je zo'n peer definieert.
public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
Inherits RangeBaseAutomationPeer
End Class
Zie voor een voorbeeldimplementatie de C#- of Visual Basic-broncode die een aangepast NumericUpDown-besturingselement implementeert en gebruikt.
Gebeurtenissen genereren
Automation-clients kunnen zich abonneren op automatiseringsevenementen. Aangepaste controlelementen moeten wijzigingen in de controlestatus rapporteren door de RaiseAutomationEvent-methode aan te roepen. Als een eigenschapswaarde wordt gewijzigd, roept u ook de methode RaisePropertyChangedEvent aan. De volgende code laat zien hoe u het peer-object kunt ophalen uit de besturingscode en een methode aanroept om een gebeurtenis te genereren. Als optimalisatie bepaalt de code of er listeners zijn voor dit gebeurtenistype. Het genereren van de gebeurtenis alleen wanneer er luisteraars zijn, voorkomt onnodige overhead en helpt het besturingselement om responsief te blijven.
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
Zie ook
- Overzicht van UI Automation
- Server-Side implementatie van de UI Automation-provider
- NumericUpDown aangepaste bediening (C#) op GitHub
- aangepast besturingselement voor NumericUpDown (Visual Basic) op GitHub
.NET Desktop feedback