Sdílet prostřednictvím


Automatizace uživatelského rozhraní vlastního ovládacího prvku WPF

Automatizace uživatelského rozhraní poskytuje jedno generalizované rozhraní, pomocí kterého můžou klienti automatizace zkoumat nebo provozovat uživatelská rozhraní různých platforem a architektur. Automatizace uživatelského rozhraní umožňuje jak kód kontroly kvality (testování), tak aplikace přístupnosti, jako jsou čtečky obrazovky, zkoumat prvky uživatelského rozhraní a simulovat interakci uživatelů s nimi z jiného kódu. Informace o automatizaci uživatelského rozhraní na všech platformách najdete v tématu Přístupnost.

Toto téma popisuje, jak implementovat zprostředkovatele automatizace uživatelského rozhraní na straně serveru pro vlastní ovládací prvek, který běží v aplikaci WPF. WPF podporuje automatizaci uživatelského rozhraní prostřednictvím stromu automatizačních objektů, které paralelně odpovídají stromu prvků uživatelského rozhraní. Testování kódu a aplikací, které poskytují funkce přístupnosti, může používat objekty automatizačního partnera přímo (pro lokální kód) nebo prostřednictvím generalizovaného rozhraní poskytovaného UI Automation.

Třídy partnerského uzlu automatizace

Ovládací prvky WPF podporují automatizaci uživatelského rozhraní prostřednictvím stromu partnerských tříd odvozených z AutomationPeer. Podle konvence začínají názvy partnerských tříd názvem třídy ovládacího prvku a končí na "AutomationPeer". Například ButtonAutomationPeer je souběžná třída pro ovládací třídu Button. Partnerské třídy jsou zhruba ekvivalentní typům ovládacích prvků automatizace uživatelského rozhraní, ale jsou specifické pro prvky WPF. Kód automatizace, který přistupuje k aplikacím WPF prostřednictvím rozhraní automatizace uživatelského rozhraní, nepoužívá partnerské vztahy automatizace přímo, ale kód automatizace ve stejném procesním prostoru může používat partnerské vztahy automatizace přímo.

Vestavěné automatizační partnerské třídy

Prvky implementují třídu automatizačního partnera, pokud přijímají interakce uživatelského rozhraní od uživatele, nebo pokud obsahují informace potřebné pro uživatele aplikací čtečky obrazovky. Ne všechny vizuální prvky WPF mají automatizační partnery. Příklady tříd, které implementují automatizační partnery, jsou Button, TextBoxa Label. Příklady tříd, které neimplementují partnerské vztahy automatizace, jsou třídy odvozené z Decorator, například Border, a třídy založené na Panel, například Grid a Canvas.

Základní Control třída nemá odpovídající protějškovou třídu. Pokud potřebujete třídu peeru, která odpovídá vlastnímu ovládacímu prvku odvozeného z Control, měli byste odvodit vlastní třídu peer z FrameworkElementAutomationPeer.

Důležité informace o zabezpečení pro odvozené partnerské vztahy

Partnerské vztahy automatizace musí běžet v prostředí s částečnou důvěryhodností. Kód v sestavení UIAutomationClient není nakonfigurovaný tak, aby běžel v prostředí s částečnou důvěryhodností, a kód partnerského uzlu automatizace by neměl odkazovat na toto sestavení. Místo toho byste měli použít třídy v sestavení UIAutomationTypes. Měli byste například použít třídu AutomationElementIdentifiers ze sestavení UIAutomationTypes, která odpovídá AutomationElement třídy v sestavení UIAutomationClient. V kódu partnerského uzlu automatizace je bezpečné odkazovat na sestavení UIAutomationTypes.

Navigace mezi vrstevníky

Po nalezení partnera automatizace může kód v rámci procesu navigovat v partnerském stromu voláním metod objektu GetChildren a GetParent. Navigace mezi prvky WPF v rámci ovládacího prvku je podporována implementací peera metody GetChildrenCore. Systém automatizace uživatelského rozhraní volá tuto metodu k vytvoření stromu dílčích prvků obsažených v ovládacím prvku; Například položky seznamu v seznamu. Výchozí metoda UIElementAutomationPeer.GetChildrenCore prochází vizuální strom elementů a vytváří strom automatizačních partnerů. Vlastní ovládací prvky přepíší tuto metodu, aby zpřístupnily podřízené prvky klientům automatizace a vrátily automatizační partnery prvků, které sdělují informace nebo umožňují uživatelskou interakci.

Vlastní nastavení odvozeného uzlu

Všechny třídy odvozené z UIElement a ContentElement obsahují chráněnou virtuální metodu OnCreateAutomationPeer. WPF volá OnCreateAutomationPeer k získání objektu partnerského uzlu automatizace pro každý ovládací prvek. Kód automatizace může použít partnerský vztah k získání informací o vlastnostech a funkcích ovládacího prvku a k simulaci interaktivního použití. Vlastní ovládací prvek, který podporuje automatizaci, musí přepsat OnCreateAutomationPeer a vrátit instanci třídy, která je odvozena z AutomationPeer. Například pokud je vlastní ovládací prvek odvozen z třídy ButtonBase, objekt vrácený OnCreateAutomationPeer by měl být odvozen z ButtonBaseAutomationPeer.

Při implementaci vlastního ovládacího prvku je nutné přepsat "Core" metody ze třídy základního automatizačního partnera, které popisují chování jedinečné a specifické pro váš vlastní ovládací prvek.

Přepsat OnCreateAutomationPeer

Přepište OnCreateAutomationPeer metodu vlastního ovládacího prvku tak, aby vrátil objekt zprostředkovatele, který musí být odvozen přímo nebo nepřímo z AutomationPeer.

Přepsat GetPattern

Automatizační partneři zjednodušují některé aspekty implementace poskytovatelů automatizace uživatelského rozhraní na straně serveru, ale automatizační partneři vlastních ovládacích prvků musí stále zpracovávat rozhraní vzorů. Podobně jako poskytovatelé jiní než WPF podporují vrstevníci vzory řízení tím, že poskytují implementace rozhraní v System.Windows.Automation.Provider oboru názvů, například IInvokeProvider. Rozhraní řídicího vzoru může být implementováno samotným peerem nebo jiným objektem. Implementace uzlu peer GetPattern vrátí objekt, který podporuje zadaný vzor. Kód automatizace uživatelského rozhraní volá metodu GetPattern a určuje PatternInterface hodnotu výčtu. Přepsání GetPattern by mělo vrátit objekt, který implementuje zadaný vzor. Pokud ovládací prvek nemá vlastní implementaci vzoru, můžete volat implementaci základního typu GetPattern a načíst její implementaci nebo hodnotu null, pokud tento model není pro tento typ ovládacího prvku podporován. Například vlastní ovládací prvek NumericUpDown lze nastavit na hodnotu v určitém rozsahu, takže jeho UI Automation peer implementuje rozhraní IRangeValueProvider. Následující příklad ukazuje, jak je metoda GetPattern partnerského uzlu přepsána, aby reagovala na hodnotu 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

Metoda GetPattern může také zadat dílčí prvek jako zprostředkovatele vzoru. Následující kód ukazuje, jak ItemsControl přenáší zpracování posouvacího vzoru na peer pro svůj interní ovládací prvek 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  

Pokud chcete zadat dílčí prvek pro zpracování vzorů, tento kód získá objekt subelementu, vytvoří protiklad pomocí metody CreatePeerForElement, nastaví vlastnost EventsSource nového protikladu na aktuální protiklad a vrátí nový protiklad. Nastavení EventsSource na dílčím prvku zabrání, aby se dílčí prvek objevil ve stromu relací automatizace a označí všechny události vyvolané dílčím prvkem jako pocházející z ovládacího prvku zadaného v EventsSource. Ovládací prvek ScrollViewer se ve stromu automatizace nezobrazuje a události, které generuje, pocházejí z objektu ItemsControl.

Přepsání "základních" metod

Kód pro automatizaci získává informace o vašem ovládacím prvku voláním veřejných metod vrstevnické třídy. Pokud chcete poskytnout informace o ovládacím prvku, přepište každou metodu, jejíž název končí na "Core", když se implementace ovládacího prvku liší od té, kterou poskytuje základní automatizační partnerská třída. Alespoň váš ovládací prvek musí implementovat GetClassNameCore a GetAutomationControlTypeCore metody, jak je znázorněno v následujícím příkladu.

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

Implementace GetAutomationControlTypeCore popisuje kontrolu vrácením hodnoty ControlType. I když můžete vrátit ControlType.Custom, měli byste vrátit jeden z konkrétnějších typů ovládacích prvků, pokud přesně popisuje váš ovládací prvek. Návratová hodnota ControlType.Custom vyžaduje dodatečnou práci od poskytovatele k implementaci automatizace uživatelského rozhraní a klientské produkty této automatizace nejsou schopny předvídat strukturu ovládání, interakci s klávesnicí ani možné vzory ovládacích prvků.

Implementujte IsContentElementCore a IsControlElementCore metody, které označují, jestli váš ovládací prvek obsahuje datový obsah nebo splňuje interaktivní roli v uživatelském rozhraní (nebo obojím). Ve výchozím nastavení vrátí obě metody true. Tato nastavení zlepšují použitelnost automatizačních nástrojů, jako jsou čtečky obrazovky, které můžou tyto metody použít k filtrování stromu automatizace. Pokud vaše metoda GetPattern přenese zpracování vzoru do uzlu dílčího prvku, může metoda IsControlElementCore uzlu dílčího prvku vrátit hodnotu false a skrýt ho ve stromu automatizace. Například posouvání v ListBox zpracovává ScrollViewera automatizační společník pro PatternInterface.Scroll je vrácen metodou GetPattern třídy ScrollViewerAutomationPeer, která je přidružena k ListBoxAutomationPeer. Proto metoda IsControlElementCore třídy ScrollViewerAutomationPeer vrátí false, takže ScrollViewerAutomationPeer se ve stromu automatizace nezobrazí.

Váš partner automatizace by měl poskytovat odpovídající výchozí hodnoty pro váš ovládací prvek. Mějte na paměti, že XAML, který odkazuje na váš ovládací prvek, může přepsat vaše rovnocenné implementace základních metod přidáním atributů AutomationProperties. Například následující XAML vytvoří tlačítko se dvěma přizpůsobenými vlastnostmi automatizace uživatelského rozhraní.

<Button AutomationProperties.Name="Special"
    AutomationProperties.HelpText="This is a special button."/>  

Implementace poskytovatelů vzorů

Rozhraní implementovaná vlastním poskytovatelem jsou explicitně deklarována, pokud je příslušný prvek odvozený přímo z Control. Například následující kód deklaruje pro Control odpovídající entitu, která implementuje rozsahovou hodnotu.

public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }  
Public Class RangePeer1  
    Inherits FrameworkElementAutomationPeer  
    Implements IRangeValueProvider  
End Class  

Pokud je vlastnící ovládací prvek odvozen z určitého typu ovládacího prvku, jako je například RangeBase, může být vrstevník odvozen z ekvivalentní odvozené třídy vrstevníka. V tomto případě by instance typu peer byla odvozena z RangeBaseAutomationPeer, který poskytuje základní implementaci IRangeValueProvider. Následující kód ukazuje deklaraci takového uzlu.

public class RangePeer2 : RangeBaseAutomationPeer { }  
Public Class RangePeer2  
    Inherits RangeBaseAutomationPeer  
End Class  

Příklad implementace najdete v zdrojovém kódu jazyka C# nebo jazyka Visual Basic, který implementuje a používá vlastní ovládací prvek NumericUpDown.

Vyvolávání událostí

Klienti automation se můžou přihlásit k odběru událostí automatizace. Vlastní ovládací prvky musí hlásit změny stavu řízení voláním metody RaiseAutomationEvent. Podobně, když se změní hodnota vlastnosti, zavolejte RaisePropertyChangedEvent metodu. Následující kód ukazuje, jak získat peer objekt z řídicího kódu a volat metodu pro vyvolání události. Pro optimalizaci kód určuje, zda pro tento typ události existují nějací naslouchací. Vyvolání události pouze při přítomnosti posluchačů se vyhne zbytečné režii a pomáhá ovládacímu prvku zůstat responzivní.

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

Viz také