Peer di automazione personalizzati
Descrive il concetto di peer di automazione per Automazione interfaccia utente Microsoft e come è possibile fornire supporto di automazione per la propria classe di interfaccia utente personalizzata.
L'automazione dell'interfaccia utente fornisce un framework che i client di automazione possono utilizzare per esaminare o utilizzare le interfacce utente di una varietà di piattaforme e framework dell'interfaccia utente. Se stai scrivendo un'app di Windows, le classi usate per l'interfaccia utente forniscono già supporto Automazione interfaccia utente. È possibile derivare da classi esistenti non sealed per definire un nuovo tipo di controllo dell'interfaccia utente o classe di supporto. In questo modo, la classe potrebbe aggiungere un comportamento che deve avere supporto per l'accessibilità, ma che il supporto Automazione interfaccia utente predefinito non copre. In questo caso, è necessario estendere il supporto Automazione interfaccia utente esistente derivando dalla classe AutomationPeer usata dall'implementazione di base, aggiungendo il supporto necessario all'implementazione peer e informando l'infrastruttura di controllo delle app di Windows che deve creare il nuovo peer.
Automazione interfaccia utente abilita non solo le applicazioni di accessibilità e le tecnologie di assistive technology, ad esempio le utilità per la lettura dello schermo, ma anche il codice di controllo della qualità (test). In entrambi gli scenari, Automazione interfaccia utente client possono esaminare gli elementi dell'interfaccia utente e simulare l'interazione dell'utente con l'app da altro codice all'esterno dell'app. Per informazioni sulle Automazione interfaccia utente su tutte le piattaforme e sul suo significato più ampio, vedi panoramica di Automazione interfaccia utente.
Esistono due gruppi di destinatari distinti che usano il framework di Automazione interfaccia utente.
- Automazione interfaccia utente client chiamano le API Automazione interfaccia utente per ottenere informazioni su tutta l'interfaccia utente attualmente visualizzata all'utente. Ad esempio, una tecnologia assistive come un'utilità per la lettura dello schermo funge da client Automazione interfaccia utente. L'interfaccia utente viene presentata come albero di elementi di automazione correlati. Il client Automazione interfaccia utente potrebbe essere interessato a una sola app alla volta o all'intero albero. Il client Automazione interfaccia utente può usare Automazione interfaccia utente API per spostarsi nell'albero e leggere o modificare le informazioni negli elementi di automazione.
- Automazione interfaccia utente provider contribuiscono alle informazioni sull'albero Automazione interfaccia utente, implementando API che espongono gli elementi nell'interfaccia utente introdotti come parte dell'app. Quando si crea un nuovo controllo, si dovrebbe ora agire come partecipante nello scenario del provider di Automazione interfaccia utente. In qualità di provider, è necessario assicurarsi che tutti i client Automazione interfaccia utente possano usare il framework Automazione interfaccia utente per interagire con il controllo sia a scopo di accessibilità che di test.
In genere sono presenti API parallele nel framework di Automazione interfaccia utente: un'API per i client Automazione interfaccia utente e un'altra api denominata in modo analogo per i provider di Automazione interfaccia utente. Nella maggior parte dei casi, questo argomento illustra le API per il provider di Automazione interfaccia utente e in particolare le classi e le interfacce che consentono l'estendibilità del provider in tale framework dell'interfaccia utente. In alcuni casi vengono menzionate Automazione interfaccia utente API usate dai client Automazione interfaccia utente, per fornire una prospettiva o fornire una tabella di ricerca che correla le API client e provider. Per altre info sulla prospettiva del client, vedi Automazione interfaccia utente Guida per programmatori client.
Nota
Automazione interfaccia utente i client in genere non usano codice gestito e in genere non vengono implementati come app UWP (in genere sono app desktop). Automazione interfaccia utente si basa su uno standard e non su un'implementazione o un framework specifico. Molti client di Automazione interfaccia utente esistenti, tra cui prodotti di assistive technology, come le utilità per la lettura dello schermo, usano interfacce COM (Component Object Model) per interagire con Automazione interfaccia utente, il sistema e le app eseguite nelle finestre figlio. Per altre info sulle interfacce COM e su come scrivere un client Automazione interfaccia utente tramite COM, vedi Automazione interfaccia utente Fundamentals.
Determinazione dello stato esistente del supporto di Automazione interfaccia utente per la classe dell'interfaccia utente personalizzata
Prima di tentare di implementare un peer di automazione per un controllo personalizzato, è necessario verificare se la classe di base e il peer di automazione forniscono già il supporto per l'accessibilità o l'automazione necessari. In molti casi, la combinazione di implementazioni FrameworkElementAutomationPeer , peer specifici e i modelli implementati possono offrire un'esperienza di accessibilità di base ma soddisfacente. Il fatto che ciò sia vero dipende dal numero di modifiche apportate all'esposizione del modello a oggetti al controllo rispetto alla relativa classe di base. Questo dipende anche dal fatto che le aggiunte alla funzionalità della classe di base siano correlate ai nuovi elementi dell'interfaccia utente nel contratto modello o all'aspetto visivo del controllo. In alcuni casi le modifiche potrebbero introdurre nuovi aspetti dell'esperienza utente che richiedono un supporto aggiuntivo per l'accessibilità.
Anche se l'uso della classe peer di base esistente fornisce il supporto di accessibilità di base, è comunque consigliabile definire un peer in modo da poter segnalare informazioni specifiche di ClassName a Automazione interfaccia utente per scenari di test automatizzati. Questa considerazione è particolarmente importante se si sta scrivendo un controllo destinato al consumo di terze parti.
Classi peer di automazione
La piattaforma UWP si basa su tecniche e convenzioni di Automazione interfaccia utente esistenti usate dai framework dell'interfaccia utente con codice gestito precedenti, ad esempio Windows Form, Windows Presentation Foundation (WPF) e Microsoft Silverlight. Molte classi di controllo e la loro funzione e scopo hanno anche la loro origine in un framework dell'interfaccia utente precedente.
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 di controllo Button.
Nota
Ai fini di questo argomento, le proprietà correlate all'accessibilità sono più importanti quando si implementa un peer di controllo. Tuttavia, per un concetto più generale di supporto Automazione interfaccia utente, è consigliabile implementare un peer in base alle raccomandazioni, come documentato dalla Guida per programmatori del provider Automazione interfaccia utente e Automazione interfaccia utente Nozioni fondamentali. Questi argomenti non riguardano le API AutomationPeer specifiche che userai per fornire le informazioni nel framework UWP per Automazione interfaccia utente, ma descrivono le proprietà che identificano la classe o forniscono altre informazioni o interazione.
Peer, modelli e tipi di controllo
Un pattern di controllo è un'implementazione dell'interfaccia che espone un particolare aspetto della funzionalità di un controllo a un client Automazione interfaccia utente. Automazione interfaccia utente client usano le proprietà e i metodi esposti tramite un pattern di controllo per recuperare informazioni sulle funzionalità del controllo o per modificare il comportamento del controllo in fase di esecuzione.
I pattern di controllo rappresentano un metodo di classificazione ed esposizione della funzionalità di un controllo indipendentemente dal tipo o dall'aspetto del controllo stesso. Ad esempio, un controllo che presenta un'interfaccia tabulare usa il pattern di controllo Grid per esporre il numero di righe e colonne nella tabella e per consentire a un client Automazione interfaccia utente di recuperare elementi dalla tabella. Come altri esempi, il client dell'automazione dell'interfaccia utente può utilizzare il pattern di controllo Invoke per i controlli che possono essere richiamati, come i pulsanti e il pattern di controllo Scroll per i controlli con barre di scorrimento, come le caselle di riepilogo, le visualizzazioni elenco o le caselle combinate. Ciascun modello di controllo rappresenta un tipo separato di funzionalità e i modelli di controllo possono essere combinati per descrivere l'insieme completo di funzionalità supportate da un particolare controllo.
I modelli di controllo si riferiscono all'interfaccia utente come le interfacce si riferiscono agli oggetti COM. In COM, è possibile eseguire query su oggetto per chiedere quali interfacce sono supportate e quindi usare tali interfacce per accedere alla funzionalità. In Automazione interfaccia utente, i client di automazione interfaccia utente possono eseguire una query su un elemento di automazione interfaccia utente per individuare i pattern di controllo supportati e quindi interagire con l'elemento e il relativo controllo peering tramite le proprietà, i metodi, gli eventi e le strutture esposti dai pattern di controllo supportati.
Uno degli scopi principali di un peer di automazione è segnalare a un client Automazione interfaccia utente che i pattern di controllo che l'elemento dell'interfaccia utente può supportare tramite il peer. A tale scopo, Automazione interfaccia utente provider implementano nuovi peer che modificano il comportamento del metodo GetPattern eseguendo l'override del metodo GetPatternCore. Automazione interfaccia utente client effettuano chiamate mappate dal provider Automazione interfaccia utente alla chiamata a GetPattern. Automazione interfaccia utente i client eseguono query per ogni modello specifico con cui vogliono interagire. Se il peer supporta il modello, restituisce un riferimento a un oggetto a se stesso; in caso contrario restituisce Null. Se il valore restituito non è Null, il client Automazione interfaccia utente prevede che possa chiamare api dell'interfaccia del pattern come client per interagire con tale pattern di controllo.
Un tipo di controllo è un modo per definire in generale la funzionalità di un controllo rappresentato dal peer. Si tratta di un concetto diverso da quello di un pattern di controllo, perché mentre un criterio informa Automazione interfaccia utente quali informazioni può ottenere o quali azioni può eseguire tramite una particolare interfaccia, il tipo di controllo esiste un livello superiore a quello. Ogni tipo di controllo include indicazioni su questi aspetti di Automazione interfaccia utente:
- Automazione interfaccia utente pattern di controllo: un tipo di controllo può supportare più di un modello, ognuno dei quali rappresenta una classificazione diversa delle informazioni o dell'interazione. Ogni tipo di controllo dispone di un set di pattern di controllo che il controllo deve supportare, un set facoltativo e un set che il controllo non deve supportare.
- Automazione interfaccia utente valori delle proprietà: ogni tipo di controllo include un set di proprietà che il controllo deve supportare. Queste sono le proprietà generali, come descritto in Automazione interfaccia utente Panoramica delle proprietà, non quelle specifiche del modello.
- Automazione interfaccia utente eventi: ogni tipo di controllo include un set di eventi che il controllo deve supportare. Anche in questo caso sono generali, non specifici del modello, come descritto in Panoramica degli eventi di Automazione interfaccia utente.
- Automazione interfaccia utente struttura ad albero: ogni tipo di controllo definisce la modalità di visualizzazione del controllo nella struttura ad albero Automazione interfaccia utente.
Indipendentemente dal modo in cui vengono implementati i peer di automazione per il framework, Automazione interfaccia utente funzionalità client non è associata alla piattaforma UWP e, di fatto, è probabile che i client esistenti Automazione interfaccia utente come assistive technology usino altri modelli di programmazione, ad esempio COM. In COM i client possono eseguire QueryInterface per l'interfaccia del pattern di controllo COM che implementa il modello richiesto o il framework di Automazione interfaccia utente generale per proprietà, eventi o esame albero. Per i modelli, il framework Automazione interfaccia utente esegue il marshalling del codice dell'interfaccia nel codice UWP in esecuzione sul provider Automazione interfaccia utente dell'app e sul peer pertinente.
Quando implementi modelli di controllo per un framework di codice gestito, ad esempio un'app UWP con C# o Microsoft Visual Basic, puoi usare le interfacce .NET Framework per rappresentare questi modelli anziché usare la rappresentazione dell'interfaccia COM. Ad esempio, l'interfaccia del modello di Automazione interfaccia utente per un'implementazione del provider Microsoft .NET del modello Invoke è IInvokeProvider.
Per un elenco dei pattern di controllo, delle interfacce del provider e dei relativi scopi, vedere Pattern e interfacce di controllo. Per l'elenco dei tipi di controllo, vedere Panoramica dei tipi di controllo Automazione interfaccia utente.
Linee guida per l'implementazione dei pattern di controllo
I pattern di controllo e gli elementi destinati fanno parte di una definizione più ampia del framework di Automazione interfaccia utente e non si applicano solo al supporto per l'accessibilità per un'app UWP. Quando si implementa un pattern di controllo, assicurarsi di implementarlo in modo che corrisponda alle indicazioni descritte in questi documenti e anche nella specifica Automazione interfaccia utente. Se si cercano indicazioni, è in genere possibile usare la documentazione Microsoft e non è necessario fare riferimento alla specifica. Le linee guida per ogni modello sono documentate qui: Implementazione di modelli di controllo Automazione interfaccia utente. Si noterà che ogni argomento in questa area include una sezione "Linee guida e convenzioni di implementazione" e "Membri obbligatori". Le linee guida fanno in genere riferimento a API specifiche dell'interfaccia del pattern di controllo pertinente nelle informazioni di riferimento sulle interfacce del pattern di controllo per i provider . Queste interfacce sono le interfacce native/COM e le relative API usano la sintassi com. Ma tutto quello che vedi ha un equivalente nello spazio dei nomi Windows.UI.Xaml.Automation.Provider.
Se si usano i peer di automazione predefiniti ed espandendone il comportamento, tali peer sono già stati scritti in conformità alle linee guida Automazione interfaccia utente. Se supportano i pattern di controllo, è possibile basarsi su tale modello di supporto conforme alle linee guida riportate in Implementazione di modelli di controllo Automazione interfaccia utente. Se un peer di controllo segnala che è rappresentativo di un tipo di controllo definito da Automazione interfaccia utente, le indicazioni documentate in Supporto dei tipi di controllo Automazione interfaccia utente sono state seguite da tale peer.
Tuttavia, potrebbero essere necessarie indicazioni aggiuntive per i pattern di controllo o i tipi di controllo per seguire le raccomandazioni Automazione interfaccia utente nell'implementazione peer. Ciò sarebbe particolarmente vero se stai implementando il supporto del tipo di controllo o del modello che non esiste ancora come implementazione predefinita in un controllo UWP. Ad esempio, il modello per le annotazioni non viene implementato in nessuno dei controlli XAML predefiniti. Tuttavia, potresti avere un'app che usa le annotazioni in modo esteso e quindi vuoi visualizzare tale funzionalità per essere accessibile. Per questo scenario, il peer deve implementare IAnnotationProvider e dovrebbe probabilmente segnalare se stesso come tipo di controllo Document con proprietà appropriate per indicare che i documenti supportano l'annotazione.
È consigliabile usare le linee guida visualizzate per i modelli in Implementazione di modelli di controllo Automazione interfaccia utente o tipi di controllo in Supporto dei tipi di controllo Automazione interfaccia utente come orientamento e indicazioni generali. È anche possibile provare a seguire alcuni dei collegamenti API per le descrizioni e le osservazioni allo scopo delle API. Tuttavia, per le specifiche della sintassi necessarie per la programmazione di app UWP, trovare l'API equivalente nello spazio dei nomi Windows.UI.Xaml.Automation.Provider e usare tali pagine di riferimento per altre info.
Classi peer di automazione integrate
In generale, gli elementi implementano una classe peer di automazione se accettano l'attività dell'interfaccia utente dall'utente o se contengono informazioni necessarie agli utenti di tecnologie di assistive technology che rappresentano l'interfaccia utente interattiva o significativa delle app. Non tutti gli oggetti visivi UWP dispongono di peer di automazione. Esempi di classi che implementano peer di automazione sono Button e TextBox. Esempi di classi che non implementano peer di automazione sono Border e classi basate su Panel, ad esempio Grid e Canvas. Un pannello non ha peer perché fornisce un comportamento di layout che è solo visivo. Non esiste un modo rilevante per l'accessibilità per consentire all'utente di interagire con un pannello. Gli elementi figlio contenuti in un pannello vengono invece segnalati agli alberi Automazione interfaccia utente come elementi figlio dell'elemento padre successivo disponibile nell'albero con una rappresentazione peer o elemento.
limiti dei processi UWP e Automazione interfaccia utente
In genere, Automazione interfaccia utente codice client che accede a un'app UWP viene eseguito out-of-process. L'infrastruttura del framework Automazione interfaccia utente consente alle informazioni di attraversare il limite del processo. Questo concetto è illustrato in modo più dettagliato in Automazione interfaccia utente Nozioni fondamentali.
OnCreateAutomationPeer
Tutte le classi che derivano da UIElement contengono il metodo virtuale protetto OnCreateAutomationPeer. La sequenza di inizializzazione dell'oggetto per i peer di automazione chiama OnCreateAutomationPeer per ottenere l'oggetto peer di automazione per ogni controllo e quindi costruire un albero Automazione interfaccia utente per l'uso in fase di esecuzione. Il codice di automazione dell'interfaccia utente può usare il peer per ottenere informazioni sulle funzionalità e le caratteristiche di un controllo e per simulare l'uso interattivo attraverso i suoi schemi di controllo. 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 deve derivare da ButtonBaseAutomationPeer.
Se si scrive una classe di controllo personalizzata e si intende fornire anche un nuovo peer di automazione, è necessario eseguire l'override del metodo OnCreateAutomationPeer per il controllo personalizzato in modo che restituisca una nuova istanza del peer. La classe peer deve derivare direttamente o indirettamente da AutomationPeer.
Ad esempio, il codice seguente dichiara che il controllo NumericUpDown
personalizzato deve usare il peer NumericUpDownPeer
a scopo di Automazione interfaccia utente.
using Windows.UI.Xaml.Automation.Peers;
...
public class NumericUpDown : RangeBase {
public NumericUpDown() {
// other initialization; DefaultStyleKey etc.
}
...
protected override AutomationPeer OnCreateAutomationPeer()
{
return new NumericUpDownAutomationPeer(this);
}
}
Public Class NumericUpDown
Inherits RangeBase
' other initialization; DefaultStyleKey etc.
Public Sub New()
End Sub
Protected Overrides Function OnCreateAutomationPeer() As AutomationPeer
Return New NumericUpDownAutomationPeer(Me)
End Function
End Class
// NumericUpDown.idl
namespace MyNamespace
{
runtimeclass NumericUpDown : Windows.UI.Xaml.Controls.Primitives.RangeBase
{
NumericUpDown();
Int32 MyProperty;
}
}
// NumericUpDown.h
...
struct NumericUpDown : NumericUpDownT<NumericUpDown>
{
...
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer()
{
return winrt::make<MyNamespace::implementation::NumericUpDownAutomationPeer>(*this);
}
};
//.h
public ref class NumericUpDown sealed : Windows::UI::Xaml::Controls::Primitives::RangeBase
{
// other initialization not shown
protected:
virtual AutomationPeer^ OnCreateAutomationPeer() override
{
return ref new NumericUpDownAutomationPeer(this);
}
};
Nota
L'implementazione onCreateAutomationPeer non deve eseguire operazioni oltre a inizializzare una nuova istanza del peer di automazione personalizzato, passando il controllo chiamante come proprietario e restituendo tale istanza. Non tentare logica aggiuntiva in questo metodo. In particolare, qualsiasi logica che potrebbe causare la distruzione di AutomationPeer all'interno della stessa chiamata può comportare un comportamento di runtime imprevisto.
Nelle implementazioni tipiche di OnCreateAutomationPeer, il proprietario viene specificato come questo o Me perché l'override del metodo si trova nello stesso ambito del resto della definizione della classe di controllo.
La definizione effettiva della classe peer può essere eseguita nello stesso file di codice del controllo o in un file di codice separato. Tutte le definizioni peer esistono nello spazio dei nomi Windows.UI.Xaml.Automation.Peers che è uno spazio dei nomi separato dai controlli per cui forniscono peer. È possibile scegliere di dichiarare i peer in spazi dei nomi separati, purché si faccia riferimento agli spazi dei nomi necessari per la chiamata al metodo OnCreateAutomationPeer.
Scelta della classe base peer corretta
Assicurarsi che AutomationPeer sia derivato da una classe di base che offre la corrispondenza migliore per la logica peer esistente della classe di controllo da cui si sta derivando. Nel caso dell'esempio precedente, poiché NumericUpDown
deriva da RangeBase, è disponibile una classe RangeBaseAutomationPeer su cui basare il peer. Usando la classe peer più vicina in parallelo alla modalità di derivazione del controllo stesso, è possibile evitare di eseguire l'override di almeno alcune delle funzionalità IRangeValueProvider perché la classe peer di base lo implementa già.
La classe Base Control non dispone di una classe peer corrispondente. Se è necessario che una classe peer corrisponda a un controllo personalizzato che deriva da Control, derivare la classe peer personalizzata da FrameworkElementAutomationPeer.
Se si deriva direttamente da ContentControl, tale classe non ha un comportamento peer di automazione predefinito perché non esiste un'implementazione OnCreateAutomationPeer che fa riferimento a una classe peer. Assicurarsi quindi di implementare OnCreateAutomationPeer per usare il proprio peer o di usare FrameworkElementAutomationPeer come peer se tale livello di supporto per l'accessibilità è adeguato per il controllo.
Nota
In genere non si deriva da AutomationPeer anziché da FrameworkElementAutomationPeer. Se è stata derivata direttamente da AutomationPeer , è necessario duplicare un sacco di supporto per l'accessibilità di base che altrimenti proviene da FrameworkElementAutomationPeer.
Inizializzazione di una classe peer personalizzata
Il peer di automazione deve definire un costruttore indipendente dai tipi che usa un'istanza del controllo proprietario per l'inizializzazione di base. Nell'esempio successivo, l'implementazione passa il valore del proprietario alla base RangeBaseAutomationPeer e infine è FrameworkElementAutomationPeer che usa effettivamente il proprietario per impostare FrameworkElementAutomationPeer.Owner.
public NumericUpDownAutomationPeer(NumericUpDown owner): base(owner)
{}
Public Sub New(owner As NumericUpDown)
MyBase.New(owner)
End Sub
// NumericUpDownAutomationPeer.idl
import "NumericUpDown.idl";
namespace MyNamespace
{
runtimeclass NumericUpDownAutomationPeer : Windows.UI.Xaml.Automation.Peers.AutomationPeer
{
NumericUpDownAutomationPeer(NumericUpDown owner);
Int32 MyProperty;
}
}
// NumericUpDownAutomationPeer.h
...
struct NumericUpDownAutomationPeer : NumericUpDownAutomationPeerT<NumericUpDownAutomationPeer>
{
...
NumericUpDownAutomationPeer(MyNamespace::NumericUpDown const& owner);
};
//.h
public ref class NumericUpDownAutomationPeer sealed : Windows::UI::Xaml::Automation::Peers::RangeBaseAutomationPeer
//.cpp
public: NumericUpDownAutomationPeer(NumericUpDown^ owner);
Metodi di base di AutomationPeer
Per motivi di infrastruttura UWP, i metodi sottoponibili a override di un peer di automazione fanno parte di una coppia di metodi: il metodo di accesso pubblico usato dal provider Automazione interfaccia utente come punto di inoltro per i client Automazione interfaccia utente e il metodo di personalizzazione "Core" protetto che una classe UWP può eseguire l'override per influenzare il comportamento. La coppia di metodi viene collegata insieme per impostazione predefinita in modo che la chiamata al metodo di accesso richiami sempre il metodo "Core" parallelo con l'implementazione del provider o come fallback richiama un'implementazione predefinita dalle classi di base.
Quando implementi un peer per un controllo personalizzato, sostituisci qualsiasi metodo "Core" della classe peer di automazione di base in cui desideri esporre un comportamento univoco per il tuo controllo personalizzato. Il codice di automazione dell'interfaccia utente ottiene informazioni sul controllo tramite chiamate a metodi pubblici della classe peer. Per fornire informazioni sul controllo, eseguire l'override di ogni metodo con un nome che termina con "Core" quando l'implementazione del controllo e la progettazione creano scenari di accessibilità o altri scenari di Automazione interfaccia utente diversi da quelli supportati dalla classe peer di automazione di base.
Come minimo, ogni volta che si definisce una nuova classe peer, implementare il metodo GetClassNameCore , come illustrato nell'esempio seguente.
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
Nota
È possibile archiviare le stringhe come costanti anziché direttamente nel corpo del metodo, ma questo è per te. Per GetClassNameCore non è necessario localizzare questa stringa. La proprietà LocalizedControlType viene utilizzata ogni volta che è necessaria una stringa localizzata da un client Automazione interfaccia utente e non da ClassName.
GetAutomationControlType
Alcune tecnologie di assistive usano il valore GetAutomationControlType direttamente quando si segnalano le caratteristiche degli elementi in un albero Automazione interfaccia utente, come informazioni aggiuntive oltre al nome Automazione interfaccia utente. Se il controllo è notevolmente diverso dal controllo da cui deriva e si vuole segnalare un tipo di controllo diverso da quello segnalato dalla classe peer di base usata dal controllo, è necessario implementare un peer ed eseguire l'override di GetAutomationControlTypeCore nell'implementazione peer. Ciò è particolarmente importante se si deriva da una classe di base generalizzata, ad esempio ItemsControl o ContentControl, in cui il peer di base non fornisce informazioni precise sul tipo di controllo.
L'implementazione di GetAutomationControlTypeCore descrive il controllo restituendo un valore AutomationControlType. Sebbene sia possibile restituire AutomationControlType.Custom, è consigliabile restituire uno dei tipi di controllo più specifici se descrive in modo accurato gli scenari principali del controllo. Ecco un esempio.
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
Nota
A meno che non si specifichi AutomationControlType.Custom, non è necessario implementare GetLocalizedControlTypeCore per fornire un valore della proprietà LocalizedControlType ai client. Automazione interfaccia utente'infrastruttura comune fornisce stringhe tradotte per ogni possibile Valore AutomationControlType diverso da AutomationControlType.Custom.
GetPattern e GetPatternCore
L'implementazione di un peer di GetPatternCore restituisce l'oggetto che supporta il modello richiesto nel parametro di input. In particolare, un client Automazione interfaccia utente chiama un metodo inoltrato al metodo GetPattern del provider e specifica un valore di enumerazione PatternInterface che assegna un nome al modello richiesto. L'override di GetPatternCore deve restituire l'oggetto che implementa il modello specificato. Tale oggetto è il peer stesso, perché il peer deve implementare l'interfaccia del pattern corrispondente ogni volta che segnala che supporta un modello. Se il peer non ha un'implementazione personalizzata di un modello, ma si sa che la base del peer implementa il modello, è possibile chiamare l'implementazione del tipo di base di GetPatternCore da GetPatternCore. GetPatternCore di un peer deve restituire null se un criterio non è supportato dal peer. Tuttavia, invece di restituire null direttamente dall'implementazione, in genere si fa affidamento sulla chiamata all'implementazione di base per restituire null per qualsiasi modello non supportato.
Quando è supportato un modello, l'implementazione di GetPatternCor e può restituire questo o Me. L'aspettativa è che il client Automazione interfaccia utente eseguirà il cast del valore restituito GetPattern all'interfaccia del pattern richiesta ogni volta che non è Null.
Se una classe peer eredita da un altro peer e tutto il supporto e la creazione di report dei criteri necessari sono già gestiti dalla classe base, l'implementazione di GetPatternCore non è necessaria. Ad esempio, se si implementa un controllo di intervallo che deriva da RangeBase e il peer deriva da RangeBaseAutomationPeer, tale peer restituisce se stesso per PatternInterface.RangeValue e dispone di implementazioni funzionanti dell'interfaccia IRangeValueProvider che supporta il modello.
Anche se non è il codice letterale, questo esempio approssima l'implementazione di GetPatternCore già presente in RangeBaseAutomationPeer.
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPatternCore(patternInterface);
}
Se si implementa un peer in cui non si dispone di tutto il supporto necessario da una classe peer di base o si vuole modificare o aggiungere al set di modelli ereditati di base che il peer può supportare, è necessario eseguire l'override di GetPatternCore per consentire ai client di Automazione interfaccia utente di usare i modelli.
Per un elenco dei modelli di provider disponibili nell'implementazione UWP del supporto Automazione interfaccia utente, vedere Windows.UI.Xaml.Automation.Provider. Ogni modello ha un valore corrispondente dell'enumerazione PatternInterface, ovvero come Automazione interfaccia utente client richiedono il modello in una chiamata GetPattern.
Un peer può segnalare che supporta più modelli. In tal caso, l'override deve includere la logica del percorso restituito per ogni valore PatternInterface supportato e restituire il peer in ogni caso corrispondente. Si prevede che il chiamante richieda solo un'interfaccia alla volta e spetta al chiamante trasmettere all'interfaccia prevista.
Ecco un esempio di override di GetPatternCore per un peer personalizzato. Segnala il supporto per due modelli, IRangeValueProvider e IToggleProvider. Il controllo qui è un controllo di visualizzazione multimediale che può essere visualizzato come schermo intero (la modalità di attivazione/disattivazione) e con un indicatore di stato all'interno del quale gli utenti possono selezionare una posizione (il controllo intervallo). Questo codice proviene dall'esempio di accessibilità XAML.
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
else if (patternInterface == PatternInterface.Toggle)
{
return this;
}
return null;
}
Inoltro di modelli da sottoelementi
Un'implementazione del metodo GetPatternCore può anche specificare un sottoelemento o una parte come provider di criteri per il relativo host. In questo esempio viene simulato il modo in cui ItemsControl trasferisce la gestione dei criteri di scorrimento al peer del controllo ScrollViewer interno. Per specificare un sottoelemento per la gestione dei criteri, questo codice ottiene l'oggetto sottoelemento, crea un peer per il sottoelemento usando il metodo FrameworkElementAutomationPeer.CreatePeerForElement e restituisce il nuovo peer.
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Scroll)
{
ItemsControl owner = (ItemsControl) base.Owner;
UIElement itemsHost = owner.ItemsHost;
ScrollViewer element = null;
while (itemsHost != owner)
{
itemsHost = VisualTreeHelper.GetParent(itemsHost) as UIElement;
element = itemsHost as ScrollViewer;
if (element != null)
{
break;
}
}
if (element != null)
{
AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(element);
if ((peer != null) && (peer is IScrollProvider))
{
return (IScrollProvider) peer;
}
}
}
return base.GetPatternCore(patternInterface);
}
Altri metodi Core
Il controllo potrebbe dover supportare gli equivalenti della tastiera per gli scenari primari; per altre info sul motivo per cui potrebbe essere necessario, vedi Accessibilità tramite tastiera. L'implementazione del supporto della chiave fa necessariamente parte del codice di controllo e non del codice peer perché fa parte della logica di un controllo, ma la classe peer deve eseguire l'override dei metodi GetAcceleratorKeyCore e GetAccessKeyCore per segnalare ai client Automazione interfaccia utente quali chiavi vengono usate. Si consideri che le stringhe che segnalano le informazioni sulla chiave potrebbero essere localizzate e che pertanto provengano da risorse, non da stringhe hardcoded.
Se si fornisce un peer per una classe che supporta una raccolta, è consigliabile derivare da classi funzionali e classi peer che dispongono già di tale tipo di supporto per la raccolta. In caso contrario, i peer per i controlli che mantengono le raccolte figlio potrebbero dover eseguire l'override del metodo peer correlato alla raccolta GetChildrenCore per segnalare correttamente le relazioni padre-figlio all'albero Automazione interfaccia utente.
Implementare i metodi IsContentElementCore e IsControlElementCore per indicare se il 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à delle tecnologie assistive come gli screen reader, che possono utilizzare questi metodi per filtrare l'albero di automazione. Se il metodo GetPatternCore trasferisce la gestione dei modelli a un peer di sottoelementi, il metodo IsControlElementCore del peer di sottoelementi può restituire false per nascondere il peer di sottoelementi dall'albero di automazione.
Alcuni controlli possono supportare scenari di etichettatura, in cui una parte etichetta di testo fornisce informazioni per una parte non di testo o un controllo deve trovarsi in una relazione di etichettatura nota con un altro controllo nell'interfaccia utente. Se è possibile fornire un comportamento utile basato su classi, è possibile eseguire l'override di GetLabeledByCore per fornire questo comportamento.
GetBoundingRectangleCore e GetClickablePointCore vengono usati principalmente per scenari di test automatizzati. Se si desidera supportare test automatizzati per il controllo, è possibile eseguire l'override di questi metodi. Ciò potrebbe essere necessario per i controlli di tipo intervallo, in cui non è possibile suggerire solo un singolo punto perché l'utente fa clic nello spazio delle coordinate ha un effetto diverso su un intervallo. Ad esempio, il peer di automazione ScrollBar predefinito esegue l'override di GetClickablePointCore per restituire un valore point "not a number".
GetLiveSettingCore influenza il valore predefinito del controllo per il valore LiveSetting per Automazione interfaccia utente. Se si desidera che il controllo restituisca un valore diverso da AutomationLiveSetting.Off, è consigliabile eseguire l'override. Per altre info su ciò che LiveSetting rappresenta, vedi AutomationProperties.LiveSetting.
È possibile eseguire l'override di GetOrientationCore se il controllo dispone di una proprietà di orientamento impostabile che può essere mappata a AutomationOrientation. Le classi ScrollBarAutomationPeer e SliderAutomationPeer eseguono questa operazione.
Implementazione di base in FrameworkElementAutomationPeer
L'implementazione di base di FrameworkElementAutomationPeer fornisce alcune informazioni Automazione interfaccia utente che possono essere interpretate da varie proprietà di layout e comportamento definite a livello di framework.
- GetBoundingRectangleCore: restituisce una struttura Rect in base alle caratteristiche di layout note. Restituisce un valore Rect a 0 se IsOffscreen è true.
- GetClickablePointCore: restituisce una struttura Point in base alle caratteristiche di layout note, purché sia presente un BoundingRectangle diverso da zero.
- GetNameCore: comportamento più esteso di quanto possa essere riepilogato qui. Vedere GetNameCore. In pratica, tenta una conversione di stringa su qualsiasi contenuto noto di un ContentControl o classi correlate con contenuto. Inoltre, se è presente un valore per LabeledBy, il valore Name dell'elemento viene usato come Nome.
- HasKeyboardFocusCore: valutato in base alle proprietà FocusState e IsEnabled del proprietario. Gli elementi che non sono controlli restituiscono sempre false.
- IsEnabledCore: valutato in base alla proprietà IsEnabled del proprietario se si tratta di un Controllo. Gli elementi che non sono controlli restituiscono sempre true. Questo non significa che il proprietario è abilitato nel senso di interazione convenzionale; significa che il peer è abilitato nonostante il proprietario non abbia una proprietà IsEnabled .
- IsKeyboardFocusableCore: restituisce true se il proprietario è un controllo; in caso contrario, è false.
- IsOffscreenCore: visibilità di Collapsed nell'elemento proprietario o in uno dei relativi elementi padre equivale a un valore true per IsOffscreen. Eccezione: un oggetto Popup può essere visibile anche se gli elementi padre del proprietario non sono.
- SetFocusCore: chiama lo stato attivo.
- GetParent: chiama FrameworkElement.Parent dal proprietario e cerca il peer appropriato. Non si tratta di una coppia di override con un metodo "Core", quindi non è possibile modificare questo comportamento.
Nota
I peer UWP predefiniti implementano un comportamento usando codice nativo interno che implementa la piattaforma UWP, non necessariamente usando il codice UWP effettivo. Non sarà possibile visualizzare il codice o la logica dell'implementazione tramite reflection CLR (Common Language Runtime) o altre tecniche. Non verranno inoltre visualizzate pagine di riferimento distinte per le sostituzioni specifiche della sottoclasse del comportamento peer di base. Ad esempio, potrebbe esserci un comportamento aggiuntivo per GetNameCore di un textBoxAutomationPeer, che non verrà descritto nella pagina di riferimento AutomationPeer.GetNameCore e non è disponibile alcuna pagina di riferimento per TextBoxAutomationPeer.GetNameCore. Non esiste nemmeno una pagina di riferimento TextBoxAutomationPeer.GetNameCore . Leggere invece l'argomento di riferimento per la classe peer più immediata e cercare le note sull'implementazione nella sezione Osservazioni.
Peer e automationProperties
Il peer di automazione deve fornire valori predefiniti appropriati per le informazioni relative all'accessibilità del controllo. Si noti che qualsiasi codice dell'app che usa il controllo può eseguire l'override di alcuni di questo comportamento includendo i valori delle proprietà associate automationProperties nelle istanze del controllo. I chiamanti possono eseguire questa operazione per i controlli predefiniti o per i controlli personalizzati. Queste impostazioni migliorano l'usabilità delle tecnologie assistive come gli screen reader, che possono utilizzare questi metodi per filtrare l'albero di automazione.: <Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>
Per altre informazioni sulle proprietà associate di AutomationProperties, vedi Informazioni di base sull'accessibilità.
Alcuni dei metodi AutomationPeer esistono a causa del contratto generale del modo in cui i provider di Automazione interfaccia utente devono segnalare informazioni, ma questi metodi non vengono in genere implementati nei peer di controllo. Ciò è dovuto al fatto che si prevede che le informazioni vengano fornite dai valori automationProperties applicati al codice dell'app che usa i controlli in un'interfaccia utente specifica. Ad esempio, la maggior parte delle app definisce la relazione di etichettatura tra due controlli diversi nell'interfaccia utente applicando un valore AutomationProperties.LabeledBy. Tuttavia, LabeledByCore viene implementato in determinati peer che rappresentano relazioni tra dati o elementi in un controllo, ad esempio l'uso di una parte di intestazione per etichettare una parte del campo dati, l'assegnazione di etichette agli elementi con i relativi contenitori o scenari simili.
Implementare modelli
Si esaminerà ora come scrivere un peer per un controllo che implementa un comportamento di espansione-compressione implementando l'interfaccia del pattern di controllo per il compressione di espansione. Il peer deve abilitare l'accessibilità per il comportamento di espansione-compressione restituendo se stesso ogni volta che Viene chiamato GetPattern con un valore PatternInterface.ExpandCollapse. Il peer deve quindi ereditare l'interfaccia del provider per tale modello (IExpandCollapseProvider) e fornire implementazioni per ognuno dei membri dell'interfaccia del provider. In questo caso l'interfaccia ha tre membri di cui eseguire l'override: Expand, Collapse, ExpandCollapseState.
È utile pianificare in anticipo l'accessibilità nella progettazione API della classe stessa. Ogni volta che si ha un comportamento potenzialmente richiesto a seguito di interazioni tipiche con un utente che lavora nell'interfaccia utente o tramite un modello di provider di automazione, fornire un singolo metodo che può chiamare la risposta dell'interfaccia utente o il modello di automazione. Ad esempio, se il controllo dispone di parti del pulsante con gestori eventi cablati che possono espandere o comprimere il controllo e dispone di equivalenti da tastiera per tali azioni, questi gestori eventi chiamano lo stesso metodo che si chiama dall'interno del corpo delle implementazioni Expand o Collapse per IExpandCollapseProvider nel peer. L'uso di un metodo logico comune può anche essere un modo utile per assicurarsi che gli stati di visualizzazione del controllo vengano aggiornati per mostrare lo stato logico in modo uniforme, indipendentemente dal modo in cui è stato richiamato il comportamento.
Un'implementazione tipica è che le API del provider chiamano prima Proprietario per l'accesso all'istanza del controllo in fase di esecuzione. È quindi possibile chiamare i metodi di comportamento necessari su tale oggetto.
public class IndexCardAutomationPeer : FrameworkElementAutomationPeer, IExpandCollapseProvider {
private IndexCard ownerIndexCard;
public IndexCardAutomationPeer(IndexCard owner) : base(owner)
{
ownerIndexCard = owner;
}
}
Un'implementazione alternativa è che il controllo stesso può fare riferimento al peer. Si tratta di un modello comune se si generano eventi di automazione dal controllo, perché il metodo RaiseAutomationEvent è un metodo peer.
eventi Automazione interfaccia utente
Gli eventi dell'automazione dell'interfaccia utente si sono suddivisi nelle categorie seguenti.
Event | Descrizione |
---|---|
Modifica proprietà | Viene generato quando viene modificata una proprietà di un elemento di automazione interfaccia utente o di un pattern di controllo. Ad esempio, se un client deve monitorare una casella di controllo di un'app, può registrarsi per l'attesa di un evento di modifica per la proprietà ToggleState. Quando il controllo della casella di controllo è selezionato o deselezionato, il provider attiva l'evento e il client può agire secondo necessità. |
Azione elemento | Si attiva quando una modifica nell'interfaccia utente deriva dall'attività dell'utente o programmatica; ad esempio, quando si fa clic o si richiama un pulsante tramite lo schema Invoke. |
Modifica struttura | Viene generato quando cambia la struttura dell'albero Automazione interfaccia utente. La struttura viene modificata quando nuovi elementi dell'interfaccia utente sono resi visibili oppure vengono nascosti o rimossi dal desktop. |
Cambiamento globale | Si attiva quando si verificano azioni di interesse globale per il client, ad esempio quando lo stato attivo si sposta da un elemento a un altro o quando una finestra secondaria si chiude. Alcuni eventi non indicano necessariamente che lo stato dell'interfaccia utente è cambiato. Ad esempio, se l'utente passa a un campo di immissione testo e poi fa clic su un pulsante per aggiornare il campo, un evento TextChanged si attiva anche se l'utente non ha effettivamente modificato il testo. Durante l'elaborazione di un evento, prima di eseguire un'azione può essere necessario per un'applicazione client verificare se sia effettivamente avvenuta una modifica. |
Identificatori automationEvents
Automazione interfaccia utente eventi vengono identificati da Valori automationEvents. I valori dell'enumerazione identificano in modo univoco il tipo di evento.
Generazione di eventi
I client di automazione dell'interfaccia utente possono sottoscrivere eventi di automazione. Nel modello peer di automazione i peer per i controlli personalizzati devono segnalare modifiche allo stato di controllo rilevanti per l'accessibilità chiamando il metodo RaiseAutomationEvent. Analogamente, quando una chiave Automazione interfaccia utente valore della proprietà cambia, i peer di controlli personalizzati devono chiamare il metodo RaisePropertyChangedEvent.
Il prossimo esempio di codice mostra come ottenere l'oggetto peer dal codice di definizione del controllo e chiamare un metodo per attivare un evento da quel peer. Per ottimizzare la procedura, il codice determina se sono presenti listener per questo tipo di evento. L'attivazione dell'evento e la creazione dell'oggetto peer solo quando sono presenti ascoltatori evita un sovraccarico non necessario e aiuta il controllo a rimanere reattivo.
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
FrameworkElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}
Navigazione nel peer
Dopo aver individuato un peer di automazione, un client Automazione interfaccia utente può esplorare la struttura peer di un'app chiamando i metodi GetChildren e GetParent dell'oggetto peer. La navigazione tra gli elementi dell'interfaccia utente all'interno di un controllo è supportata dall'implementazione del metodo GetChildrenCore da parte del peer. 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 GetChildrenCore predefinito in FrameworkElementAutomationPeer attraversa la struttura ad albero visuale degli elementi per compilare l'albero dei peer di automazione. I controlli personalizzati possono sovrascrivere questo metodo per esporre una diversa rappresentazione degli elementi figlio ai client di automazione, restituendo i peer di automazione degli elementi che trasmettono informazioni o consentono l'interazione dell'utente.
Supporto per l'automazione nativa per i modelli di testo
Alcuni dei peer di automazione delle app UWP predefiniti forniscono il supporto del pattern di controllo per il modello di testo (PatternInterface.Text). Ma forniscono questo supporto tramite metodi nativi e i peer coinvolti non notano l'interfaccia ITextProvider nell'ereditarietà (gestita). Tuttavia, se un client di Automazione interfaccia utente gestito o non gestito esegue query sul peer per i modelli, indicherà il supporto per il modello di testo e fornirà il comportamento per parti del modello quando vengono chiamate le API client.
Se intendi derivare da uno dei controlli di testo dell'app UWP e crea anche un peer personalizzato che deriva da uno dei peer correlati al testo, controlla le sezioni Osservazioni per il peer per altre informazioni sul supporto a livello nativo per i modelli. È possibile accedere al comportamento di base nativo nel peer personalizzato se si chiama l'implementazione di base dalle implementazioni dell'interfaccia del provider gestito, ma è difficile modificare le operazioni eseguite dall'implementazione di base perché le interfacce native nel peer e nel relativo controllo proprietario non sono esposte. In genere è consigliabile usare le implementazioni di base così come sono (solo chiamata base) o sostituire completamente la funzionalità con il proprio codice gestito e non chiamare l'implementazione di base. Quest'ultimo è uno scenario avanzato, è necessaria una buona familiarità con il framework dei servizi di testo usato dal controllo per supportare i requisiti di accessibilità quando si usa tale framework.
AutomationProperties.AccessibilityView
Oltre a fornire un peer personalizzato, puoi anche modificare la rappresentazione della visualizzazione albero per qualsiasi istanza del controllo impostando AutomationProperties.AccessibilityView in XAML. Questa operazione non viene implementata come parte di una classe peer, ma verrà menzionata qui perché è consigliabile supportare l'accessibilità complessiva per i controlli personalizzati o per i modelli personalizzati.
Lo scenario principale per l'uso di AutomationProperties.AccessibilityView consiste nell'omettere deliberatamente determinati controlli in un modello dalle visualizzazioni Automazione interfaccia utente, perché non contribuiscono significativamente alla visualizzazione di accessibilità dell'intero controllo. Per evitare questo problema, impostare AutomationProperties.AccessibilityView su "Raw".
Generazione di eccezioni dai peer di automazione
Le API che si stanno implementando per il supporto peer di automazione sono autorizzate a generare eccezioni. È previsto che tutti i client Automazione interfaccia utente in ascolto siano abbastanza affidabili da continuare dopo la generazione della maggior parte delle eccezioni. In tutte le probabilità che il listener stia esaminando un albero di automazione all-up che include app diverse da quelle personalizzate ed è una progettazione client inaccettabile per arrestare l'intero client solo perché un'area dell'albero ha generato un'eccezione basata su peer quando il client ha chiamato le api.
Per i parametri passati al peer, è accettabile convalidare l'input e, ad esempio, generare ArgumentNullException se è stato passato null e questo non è un valore valido per l'implementazione. Tuttavia, se sono presenti operazioni successive eseguite dal peer, tenere presente che le interazioni del peer con il controllo host hanno qualcosa di un carattere asincrono. Tutto ciò che un peer non blocca necessariamente il thread dell'interfaccia utente nel controllo (e probabilmente non dovrebbe). È quindi possibile avere situazioni in cui un oggetto era disponibile o avere determinate proprietà quando il peer è stato creato o quando è stato chiamato un metodo peer di automazione, ma nel frattempo lo stato del controllo è cambiato. Per questi casi, esistono due eccezioni dedicate che un provider può generare:
- Throw ElementNotAvailableException se non è possibile accedere al proprietario del peer o a un elemento peer correlato in base alle informazioni originali passate dall'API. Ad esempio, potrebbe essere presente un peer che sta tentando di eseguire i relativi metodi, ma il proprietario è stato rimosso dall'interfaccia utente, ad esempio una finestra di dialogo modale chiusa. Per un client non-.NET, viene eseguito il mapping a UIA_E_ELEMENTNOTAVAILABLE.
- Gettare ElementNotEnabledException se esiste ancora un proprietario, ma tale proprietario è in una modalità come IsEnabled
=
false che blocca alcune delle modifiche a livello di codice specifiche che il peer sta tentando di eseguire. Per un client non-.NET, viene eseguito il mapping a UIA_E_ELEMENTNOTENABLED.
Al di là di questo, i peer devono essere relativamente conservativi riguardo alle eccezioni generate dal supporto peer. La maggior parte dei client non sarà in grado di gestire le eccezioni dai peer e di trasformarle in scelte eseguibili che gli utenti possono effettuare durante l'interazione con il client. A volte, quindi, un no-op e intercettare le eccezioni senza rigenerare all'interno delle implementazioni peer, è una strategia migliore di quella che genera eccezioni ogni volta che il peer tenta di non funzionare. Si consideri anche che la maggior parte dei client Automazione interfaccia utente non viene scritta nel codice gestito. La maggior parte è scritta in COM e cerca solo S_OK in un HRESULT ogni volta che chiamano un metodo client Automazione interfaccia utente che finisce per accedere al peer.