Automazione interfaccia utente di un controllo personalizzato WPF

Automazione interfaccia utente fornisce un'unica interfaccia generalizzata che i client di automazione possono usare per esaminare o gestire le interfacce utente di un'ampia gamma di piattaforme e framework. Automazione interfaccia utente consente sia il codice di controllo qualità (test) che le applicazioni di accessibilità, ad esempio le utilità per la lettura dello schermo, di esaminare gli elementi dell'interfaccia utente e simulare l'interazione dell'utente con loro da altri codici. Per informazioni sui Automazione interfaccia utente in tutte le piattaforme, vedere Accessibilità.

L'articolo descrive come implementare un provider di automazione interfaccia utente sul lato server per un controllo personalizzato che viene eseguito in un'applicazione WPF. WPF supporta Automazione interfaccia utente tramite un albero di oggetti di automazione peer che paralleli all'albero degli elementi dell'interfaccia utente. Il codice di test e le applicazioni che forniscono funzionalità di accessibilità possono usare oggetti peer di automazione direttamente (per il codice in-process) o tramite l'interfaccia generalizzata fornita da Automazione interfaccia utente.

Classi peer di automazione

I controlli WPF supportano Automazione interfaccia utente tramite un albero di classi peer che derivano da AutomationPeer. Per convenzione, i nomi delle classi peer iniziano con il nome della classe del controllo e terminano con "AutomationPeer". Ad esempio, ButtonAutomationPeer è la classe peer per la classe del Button controllo. Le classi peer sono approssimativamente equivalenti ai tipi di controllo Automazione interfaccia utente, ma sono specifiche degli elementi WPF. Il codice di automazione che accede alle applicazioni WPF tramite l'interfaccia Automazione interfaccia utente non usa direttamente peer di automazione, ma il codice di automazione nello stesso spazio di processo può usare direttamente peer di automazione.

Classi peer di automazione integrate

Gli elementi implementano una classe peer di automazione se accettano l'attività dell'interfaccia da parte dell'utente o se contengono le informazioni necessarie per gli utenti di applicazioni per la lettura dello schermo. Non tutti gli oggetti visivi WPF dispongono di peer di automazione. Esempi di classi che implementano peer di automazione sono Button, TextBoxe Label. Esempi di classi che non implementano peer di automazione sono classi che derivano da Decorator, ad esempio Border, e classi basate su Panel, ad esempio Grid e Canvas.

La classe base Control non dispone di una classe peer corrispondente. Se è necessaria una classe peer per corrispondere a un controllo personalizzato che deriva da Control, è necessario derivare la classe peer personalizzata da FrameworkElementAutomationPeer.

Considerazioni sulla sicurezza per i peer derivati

I peer di automazione devono essere eseguiti in un ambiente parzialmente attendibile. Il codice nell'assembly UIAutomationClient non è configurato per l'esecuzione in un ambiente parzialmente attendibile e il codice di peer di automazione non deve fare riferimento a tale assembly. È consigliabile invece usare le classi nell'assembly UIAutomationTypes. Ad esempio, è consigliabile usare la AutomationElementIdentifiers classe dell'assembly UIAutomationTypes, che corrisponde alla AutomationElement classe nell'assembly UIAutomationClient. Un modo sicuro consiste nel fare riferimento all'assembly UIAutomationTypes nel codice del peer di automazione.

Navigazione nel peer

Dopo aver individuato un peer di automazione, il codice in-process può spostarsi nell'albero peer chiamando i metodi e GetParent dell'oggettoGetChildren. La navigazione tra gli elementi WPF all'interno di un controllo è supportata dall'implementazione del peer del GetChildrenCore metodo . Il sistema di Automazione interfaccia utente chiama questo metodo per creare un albero di sottoelementi contenuti in un controllo, come ad esempio le voci di una casella di riepilogo. Il metodo predefinito UIElementAutomationPeer.GetChildrenCore attraversa la struttura ad albero visuale degli elementi per compilare l'albero dei peer di automazione. I controlli personalizzati eseguono l'override del metodo per esporre gli elementi figlio ai client di automazione, restituendo i peer di automazione di elementi che contengono informazioni o consentono l'interazione da parte dell'utente.

Personalizzazioni in un peer derivato

Tutte le classi che derivano da UIElement e ContentElement contengono il metodo OnCreateAutomationPeervirtuale protetto . Chiamate OnCreateAutomationPeer WPF per ottenere l'oggetto peer di automazione per ogni controllo. Il codice di automazione può usare il peer per ottenere informazioni sulle funzionalità e le caratteristiche di un controllo e per simulare l'uso interattivo. Un controllo personalizzato che supporta l'automazione deve eseguire l'override OnCreateAutomationPeer e restituire un'istanza di una classe che deriva da AutomationPeer. Ad esempio, se un controllo personalizzato deriva dalla ButtonBase classe , l'oggetto restituito da OnCreateAutomationPeer deve derivare da ButtonBaseAutomationPeer.

Quando si implementa un controllo personalizzato, è necessario eseguire l'override dei metodi "Core" dalla classe peer di automazione di base che descrivono il comportamento univoco e specifico del controllo personalizzato.

Override di OnCreateAutomationPeer

Eseguire l'override del metodo per il controllo personalizzato in modo che restituisca l'oggetto OnCreateAutomationPeer provider, che deve derivare direttamente o indirettamente da AutomationPeer.

Override di GetPattern

I peer di automazione semplificano alcuni aspetti di implementazione dei provider di Automazione interfaccia utente lato server, ma i peer di automazione dei controlli personalizzati devono comunque gestire le interfacce dei criteri. Analogamente ai provider non WPF, i peer supportano i modelli di controllo fornendo implementazioni di interfacce nello spazio dei System.Windows.Automation.Provider nomi, ad esempio IInvokeProvider. Le interfacce dei criteri di controllo possono essere implementate dal peer stesso o da un altro oggetto. L'implementazione del peer di GetPattern restituisce l'oggetto che supporta il modello specificato. Automazione interfaccia utente codice chiama il GetPattern metodo e specifica un PatternInterface valore di enumerazione. L'override di GetPattern deve restituire l'oggetto che implementa il modello specificato. Se il controllo non dispone di un'implementazione personalizzata di un modello, è possibile chiamare l'implementazione del tipo di base di GetPattern per recuperare l'implementazione o null se il criterio non è supportato per questo tipo di controllo. Ad esempio, un controllo NumericUpDown personalizzato può essere impostato su un valore all'interno di un intervallo, in modo che il relativo peer Automazione interfaccia utente implementi l'interfacciaIRangeValueProvider. Nell'esempio seguente viene illustrato come viene eseguito l'override del metodo del GetPattern peer per rispondere a un PatternInterface.RangeValue valore.

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

Un GetPattern metodo può anche specificare un sottoelemento come provider di criteri. Il codice seguente illustra come ItemsControl trasferisce la gestione dei criteri di scorrimento al peer del relativo controllo interno 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  

Per specificare un sottoelemento per la gestione dei criteri, questo codice ottiene l'oggetto sottoelemento, crea un peer usando il CreatePeerForElement metodo , imposta la EventsSource proprietà del nuovo peer sul peer corrente e restituisce il nuovo peer. L'impostazione EventsSource su un sottoelemento impedisce la visualizzazione del sottoelemento nell'albero peer di automazione e definisce tutti gli eventi generati dal sottoelemento come originato dal controllo specificato in EventsSource. Il ScrollViewer controllo non viene visualizzato nell'albero di automazione e gli eventi di scorrimento generati sembrano originare dall'oggetto ItemsControl .

Override dei metodi "Core"

Il codice di automazione ottiene informazioni sul controllo tramite chiamate a metodi pubblici della classe peer. Per fornire informazioni sul controllo, eseguire l'override di ogni metodo il cui nome termina con "Core" quando l'implementazione del controllo differisce da quella fornita dalla classe peer di automazione di base. Come minimo, il controllo deve implementare i GetClassNameCore metodi e GetAutomationControlTypeCore , come illustrato nell'esempio seguente.

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

L'implementazione di GetAutomationControlTypeCore descrive il controllo restituendo un ControlType valore. Sebbene sia possibile restituire ControlType.Custom, è necessario restituire uno dei tipi di controllo più specifici se descrive in modo accurato il controllo. Un valore restituito di ControlType.Custom richiede un lavoro aggiuntivo per il provider per implementare Automazione interfaccia utente e Automazione interfaccia utente prodotti client non sono in grado di prevedere la struttura di controllo, l'interazione tramite tastiera e i possibili modelli di controllo.

Implementare i metodi e IsControlElementCore per indicare se il IsContentElementCore controllo contiene contenuto di dati o svolge un ruolo interattivo nell'interfaccia utente (o entrambi). Per impostazione predefinita, entrambi i metodi restituiscono true. Queste impostazioni migliorano l'usabilità di strumenti di automazione, come le utilità per la lettura dello schermo, i quali possono usare questi metodi per filtrare l'albero di automazione. Se il metodo trasferisce la GetPattern gestione dei modelli a un peer di sottoelementi, il metodo del peer di sottoelementi può restituire false per nascondere il peer di IsControlElementCore sottoelementi dall'albero di automazione. Ad esempio, lo scorrimento in un ListBox oggetto viene gestito da un ScrollVieweroggetto e il peer di automazione per PatternInterface.Scroll viene restituito dal GetPattern metodo dell'oggetto ScrollViewerAutomationPeer associato all'oggetto ListBoxAutomationPeer. Di conseguenza, il IsControlElementCore metodo dell'oggetto ScrollViewerAutomationPeer restituisce false, in modo che l'oggetto ScrollViewerAutomationPeer non venga visualizzato nell'albero di automazione.

Il peer di automazione deve fornire valori predefiniti appropriati per il controllo. Tieni presente che XAML che fa riferimento al controllo può eseguire l'override delle implementazioni peer dei metodi di base includendo AutomationProperties attributi. Ad esempio, il codice XAML seguente crea un pulsante con due proprietà Automazione interfaccia utente personalizzate.

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

Implementare i provider di criteri

Le interfacce implementate da un provider personalizzato vengono dichiarate in modo esplicito se l'elemento proprietario deriva direttamente da Control. Ad esempio, il codice seguente dichiara un peer per un Control oggetto che implementa un valore di intervallo.

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

Se il controllo proprietario deriva da un tipo specifico di controllo, ad RangeBaseesempio , il peer può essere derivato da una classe peer derivata equivalente. In questo caso, il peer deriva da RangeBaseAutomationPeer, che fornisce un'implementazione di base di IRangeValueProvider. Il codice seguente mostra la dichiarazione di un peer di questo tipo.

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

Per un'implementazione di esempio, vedere il codice sorgente C# o Visual Basic che implementa e utilizza un controllo personalizzato NumericUpDown.

Generare eventi

I client di automazione possono sottoscrivere eventi di automazione. I controlli personalizzati devono segnalare modifiche allo stato del controllo chiamando il RaiseAutomationEvent metodo . Analogamente, quando un valore della proprietà cambia, chiamare il RaisePropertyChangedEvent metodo . Il codice seguente mostra come ottenere l'oggetto peer dall'interno del codice del controllo e chiamare un metodo per generare un evento. Per ottimizzare la procedura, il codice determina se sono presenti listener per questo tipo di evento. La generazione dell'evento solo in presenza di listener evita un sovraccarico inutile e consente al controllo di rimane pronto a rispondere.

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

Vedi anche