Delen via


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