Automazione interfaccia utente di un controllo personalizzato WPF
Microsoft UI Automation fornisce una singola interfaccia generalizzata che i client di automazione possono utilizzare per esaminare o gestire le interfacce utente di diverse piattaforme e framework. UI Automation consente al codice del controllo di qualità (test) e alle applicazioni di accessibilità, quali le utilità per la lettura dello schermo, di esaminare gli elementi dell'interfaccia utente e simularne l'interazione dell'utente da altro codice. Per informazioni sull'UI Automation in tutte le piattaforme, vedere Accessibilità.
In questo argomento viene descritto come implementare un provider di automazione interfaccia utente sul lato server per un controllo personalizzato in esecuzione in un'applicazione WPF. WPF supporta l'UI Automation tramite una struttura ad albero di oggetti peer di automazione che affianca la struttura ad albero di elementi dell'interfaccia utente. Il codice di test e le applicazioni che forniscono le funzionalità di accessibilità possono utilizzare gli oggetti peer di automazione direttamente, per il codice in-process, o tramite l'interfaccia generalizzata fornita dall'UI Automation.
Nel presente argomento sono contenute le seguenti sezioni.
- Classi peer di automazione
- Classi peer di automazione incorporate
- Considerazioni sulla sicurezza dei peer derivati
- Spostamento tra peer
- Personalizzazioni in un peer derivato
- Argomenti correlati
Classi peer di automazione
I controlli WPF supportano l'UI Automation tramite una struttura ad 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 controllo Button. Le classi peer equivalgono quasi ai tipi di controllo dell'UI Automation ma sono specifiche degli elementi WPF. Il codice di automazione che accede alle applicazioni WPF tramite l'interfaccia dell'UI Automation non utilizza direttamente i peer di automazione, mentre il codice di automazione dello stesso spazio di processo può utilizzare direttamente i peer di automazione.
Classi peer di automazione incorporate
Gli elementi implementano una classe peer di automazione se accettano l'attività dell'interfaccia dall'utente o se contengono le informazioni richieste dagli utenti delle applicazioni di utilità per la lettura dello schermo. Non tutti gli elementi WPF visivi dispongono di peer di automazione. Button, TextBox e Label sono esempi di classi che implementano i peer di automazione. Esempi di classi che non implementano i peer di automazione sono rappresentati dalle classi che derivano da Decorator, ad esempio Border, e dalle classi basate su Panel, ad esempio Grid e Canvas.
La classe Control base non dispone di una classe peer corrispondente. Se è necessaria una classe peer corrispondente a un controllo personalizzato che derivi da Control, è necessario derivare la classe peer personalizzata da FrameworkElementAutomationPeer.
Considerazioni sulla sicurezza dei peer derivati
I peer di automazione devono essere eseguiti in un ambiente ad attendibilità parziale. Il codice nell'assembly UIAutomationClient non è configurato per essere eseguito in un ambiente ad attendibilità parziale e il codice del peer di automazione non deve fare riferimento a tale assembly. È necessario invece utilizzare le classi nell'assembly UIAutomationTypes. Ad esempio, è necessario utilizzare la classe AutomationElementIdentifiers dell'assembly UIAutomationTypes che corrisponde alla classe AutomationElement dell'assembly UIAutomationClient. È consigliabile fare riferimento all'assembly UIAutomationTypes nel codice del peer di automazione.
Spostamento tra peer
Dopo avere individuato un peer di automazione, il codice in-process può spostarsi nella struttura ad albero dei peer chiamando i metodi GetChildren e GetParent dell'oggetto. La navigazione tra gli elementi WPF all'interno di un controllo è supportata dall'implementazione del peer del metodo GetChildrenCore. Il sistema di Automazione interfaccia utente chiama questo metodo per sviluppare una struttura ad albero di sottoelementi contenuti all'interno di un controllo, ad esempio gli elementi di un elenco in una casella di riepilogo. Il metodo UIElementAutomationPeer.GetChildrenCore predefinito attraversa la struttura ad albero visuale degli elementi per compilare la struttura ad albero dei peer di automazione. I controlli personalizzati eseguono l'override di questo metodo per esporre gli elementi figlio ai client di automazione, restituendo i peer di automazione degli elementi che contengono le informazioni o consentono l'interazione dell'utente.
Personalizzazioni in un peer derivato
Tutte le classi che derivano da UIElement e ContentElement contengono il metodo virtuale protetto OnCreateAutomationPeer. WPF chiama OnCreateAutomationPeer per ottenere l'oggetto peer di automazione per ogni controllo. Il codice di automazione può utilizzare il peer per ottenere informazioni sulle caratteristiche e le funzionalità di un controllo e per simulare l'utilizzo interattivo. Un controllo personalizzato che supporta l'automazione deve eseguire l'override di OnCreateAutomationPeer e restituire un'istanza di una classe che deriva da AutomationPeer. Ad esempio, se un controllo personalizzato deriva dalla classe ButtonBase, l'oggetto restituito da OnCreateAutomationPeer dovrà derivare da ButtonBaseAutomationPeer.
Quando si implementa un controllo personalizzato, è necessario eseguire l'override dei metodi "Core" che descrivono il comportamento univoco e specifico del controllo personalizzato dalla classe peer di automazione di base.
Override di OnCreateAutomationPeer
Eseguire l'override del metodo OnCreateAutomationPeer per il controllo personalizzato in modo che restituisca l'oggetto provider che deve derivare direttamente o indirettamente da AutomationPeer.
Override di GetPattern
I peer di automazione semplificano alcuni aspetti dell'implementazione dei provider di UI Automation sul lato server, ma i peer di automazione dei controlli personalizzati devono comunque gestire le interfacce dei pattern. Analogamente ai provider non WPF, i peer supportano i pattern di controllo fornendo le implementazioni di interfacce nello spazio dei nomi System.Windows.Automation.Provider, ad esempio IInvokeProvider. Le interfacce dei pattern 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 pattern specificato. Il codice di UI Automation chiama il metodo GetPattern e specifica un valore di enumerazione PatternInterface. L'override di GetPattern deve restituire l'oggetto che implementa il pattern specificato. Se il controllo non include un'implementazione personalizzata di un pattern, è possibile chiamare l'implementazione del tipo di base di GetPattern per recuperare la relativa implementazione o un valore null se il pattern non è supportato per questo tipo di controllo. Ad esempio, è possibile impostare un controllo NumericUpDown personalizzato su un valore all'interno di un intervallo, in modo che il relativo peer di UI Automation implementi l'interfaccia IRangeValueProvider. Nell'esempio seguente viene eseguito l'override del metodo GetPattern del peer in modo da rispondere a un valore PatternInterface.RangeValue.
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
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPattern(patternInterface);
}
Un metodo GetPattern può inoltre specificare un sottoelemento come provider del pattern. Nel codice seguente viene illustrato come ItemsControl trasferisce la gestione del pattern Scroll al peer del relativo controllo ScrollViewer interno.
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 del pattern, questo codice ottiene l'oggetto del sottoelemento, crea un peer tramite il metodo CreatePeerForElement, imposta la proprietà EventsSource del nuovo peer sul peer corrente e restituisce il nuovo peer. Se si imposta EventsSource in un sottoelemento, si impedisce che il sottoelemento venga visualizzato nella struttura ad albero del peer di automazione e si definiscono tutti gli eventi generati dal sottoelemento come se fossero stati originati dal controllo specificato in EventsSource. Il controllo ScrollViewer non viene visualizzato nella struttura ad albero di automazione e gli eventi di scorrimento generati risulteranno avere origine dall'oggetto ItemsControl.
Override dei metodi "Core"
Il codice di automazione ottiene informazioni sul controllo chiamando i 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. Il controllo deve implementare almeno i metodi GetClassNameCore e GetAutomationControlTypeCore, come illustrato nell'esempio seguente.
Protected Overrides Function GetClassNameCore() As String
Return "NumericUpDown"
End Function
Protected Overrides Function GetAutomationControlTypeCore() As AutomationControlType
Return AutomationControlType.Spinner
End Function
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
L'implementazione di GetAutomationControlTypeCore descrive il controllo restituendo un valore ControlType. Sebbene sia possibile restituire ControlType.Custom, è necessario restituire uno dei tipi di controllo più specifici se il controllo viene descritto in modo preciso. Un valore restituito da ControlType.Custom richiede al provider un lavoro aggiuntivo per implementare l'UI Automation e i prodotti client di UI Automation non sono in grado di prevedere la struttura del controllo, l'interazione della tastiera e i possibili pattern di controllo.
Implementare i metodi IsContentElementCore e IsControlElementCore per indicare se il controllo include contenuto di dati o svolge un ruolo interattivo nell'interfaccia utente o entrambi gli aspetti. Per impostazione predefinita, entrambi i metodi restituiscono true. Queste impostazioni migliorano l'utilizzabilità degli strumenti di automazione, ad esempio le utilità per la lettura dello schermo, che possono utilizzare questi metodi per filtrare la struttura ad albero di automazione. Se il metodo GetPattern trasferisce la gestione dei pattern a un peer del sottoelemento, il metodo IsControlElementCore del peer del sottoelemento può restituire false per nascondere il peer del sottoelemento dalla struttura ad albero di automazione. Ad esempio, lo scorrimento in un oggetto ListBox viene gestito da un oggetto ScrollViewer e il peer di automazione per PatternInterface.Scroll viene restituito dal metodo GetPattern dell'oggetto ScrollViewerAutomationPeer associato a ListBoxAutomationPeer. Pertanto, il metodo IsControlElementCore di ScrollViewerAutomationPeer restituisce false, in modo che ScrollViewerAutomationPeer non venga visualizzato nella struttura ad albero di automazione.
Il peer di automazione deve fornire i valori predefiniti appropriati per il controllo. Il codice XAML che fa riferimento al controllo può eseguire l'override delle implementazioni peer dei metodi core includendo gli attributi AutomationProperties. Ad esempio, con il codice XAML seguente viene creato un pulsante che include due proprietà di UI Automation personalizzate.
<Button AutomationProperties.Name="Special"
AutomationProperties.HelpText="This is a special button."/>
Implementazione dei provider di pattern
Le interfacce implementate da un provider personalizzato sono dichiarate in modo esplicito se l'elemento proprietario deriva direttamente da Control. Ad esempio, nel codice seguente viene dichiarato un peer per una classe Control che implementa un valore di un 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 esempio RangeBase, 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. Nel codice seguente è illustrata la dichiarazione di tale peer.
public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
Inherits RangeBaseAutomationPeer
End Class
Per un'implementazione di esempio, vedere Esempio di controllo personalizzato NumericUpDown con supporto per temi e animazione interfaccia utente (la pagina potrebbe essere in inglese).
Generazione di eventi
I client di automazione possono sottoscrivere gli eventi di automazione. I controlli personalizzati devono segnalare le modifiche allo stato del controllo chiamando il metodo RaiseAutomationEvent . Analogamente, quando viene modificato il valore di una proprietà, chiamare il metodo RaisePropertyChangedEvent. Nel codice seguente viene illustrato come ottenere l'oggetto peer dal codice del controllo e chiamare un metodo per generare un evento. Per motivi di ottimizzazione, il codice determina se sono presenti listener per questo tipo di evento. Se l'evento viene generato solo in presenza di listener si evita un inutile sovraccarico garantendo l'efficienza del controllo.
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
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}
Vedere anche
Concetti
Cenni preliminari su automazione interfaccia utente
Implementazione del provider di automazione interfaccia utente lato server
Altre risorse
Cronologia delle modifiche
Data |
Cronologia |
Motivo |
---|---|---|
Dicembre 2010 |
Aggiunta di esempi mancanti di Visual Basic. |
Correzione di bug nel contenuto. |
Luglio 2008 |
Argomento aggiunto. |
Miglioramento delle informazioni. |