Condividi tramite


Eventi personalizzati e funzioni di accesso agli eventi nei componenti Windows Runtime

Il supporto di .NET Framework per Windows Runtime semplifica la dichiarazione di eventi nei componenti di Windows Runtime nascondendo le differenze tra lo schema di eventi di Windows Runtime e quello di .NET Framework. Quando dichiari funzioni di accesso agli eventi personalizzate in un componente di Windows Runtime, devi seguire lo schema di Windows Runtime.

Quando esegui la registrazione per gestire un evento in Windows Runtime, la funzione di accesso add restituisce un token. Per annullare la registrazione, passa il token alla funzione di accesso remove. Ciò significa che le funzioni di accesso remove e add per gli eventi di Windows Runtime hanno firme diverse rispetto alle funzioni di accesso che già conosci.

I compilatori di Visual Basic e C#, per fortuna, semplificano il processo. Quando dichiari un evento con le funzioni di accesso personalizzate in un componente di Windows Runtime, i compilatori utilizzano automaticamente lo schema di Windows Runtime. Ad esempio, ricevi un errore del compilatore se la tua funzione di accesso add non restituisce un token. .NET Framework fornisce due tipi per supportare l'implementazione:

  • La struttura EventRegistrationToken rappresenta il token.

  • La classe EventRegistrationTokenTable<T> crea i token e gestisce un mapping tra token e gestori eventi. L'argomento di tipo generico è il tipo di argomento dell'evento. Crea un'istanza di questa classe per ogni evento alla prima registrazione di un gestore eventi per tale evento.

Nel codice seguente per l'evento NumberChanged viene illustrato lo schema di base per gli eventi di Windows Runtime. In questo esempio, il costruttore per l'oggetto argomento dell'evento, NumberChangedEventArgs, accetta un solo parametro Integer che rappresenta il valore numerico modificato.

Nota

Si tratta dello stesso schema utilizzato dai compilatori per gli eventi comuni dichiarati in un componente di Windows Runtime.

    private EventRegistrationTokenTable<EventHandler<NumberChangedEventArgs>> 
        m_NumberChangedTokenTable = null;

    public event EventHandler<NumberChangedEventArgs> NumberChanged
    {
        add
        {
            return EventRegistrationTokenTable<EventHandler<NumberChangedEventArgs>>
                .GetOrCreateEventRegistrationTokenTable(ref m_NumberChangedTokenTable)
                .AddEventHandler(value);
        }
        remove
        {
            EventRegistrationTokenTable<EventHandler<NumberChangedEventArgs>>
                .GetOrCreateEventRegistrationTokenTable(ref m_NumberChangedTokenTable)
                .RemoveEventHandler(value);
        }
    }

    internal void OnNumberChanged(int newValue)
    {
        EventHandler<NumberChangedEventArgs> temp = 
            EventRegistrationTokenTable<EventHandler<NumberChangedEventArgs>>
            .GetOrCreateEventRegistrationTokenTable(ref m_NumberChangedTokenTable)
            .InvocationList;
        if (temp != null)
        {
            temp(this, new NumberChangedEventArgs(newValue));
        }
    }
Private m_NumberChangedTokenTable As  _
    EventRegistrationTokenTable(Of EventHandler(Of NumberChangedEventArgs))

Public Custom Event NumberChanged As EventHandler(Of NumberChangedEventArgs)

    AddHandler(ByVal handler As EventHandler(Of NumberChangedEventArgs))
        Return EventRegistrationTokenTable(Of EventHandler(Of NumberChangedEventArgs)).
            GetOrCreateEventRegistrationTokenTable(m_NumberChangedTokenTable).
            AddEventHandler(handler)
    End AddHandler

    RemoveHandler(ByVal token As EventRegistrationToken)
        EventRegistrationTokenTable(Of EventHandler(Of NumberChangedEventArgs)).
            GetOrCreateEventRegistrationTokenTable(m_NumberChangedTokenTable).
            RemoveEventHandler(token)
    End RemoveHandler

    RaiseEvent(ByVal sender As Class1, ByVal args As NumberChangedEventArgs)
        Dim temp As EventHandler(Of NumberChangedEventArgs) = _
            EventRegistrationTokenTable(Of EventHandler(Of NumberChangedEventArgs)).
            GetOrCreateEventRegistrationTokenTable(m_NumberChangedTokenTable).
            InvocationList
        If temp IsNot Nothing Then
            temp(sender, args)
        End If
    End RaiseEvent
End Event

Il metodo GetOrCreateEventRegistrationTokenTable static (Shared in Visual Basic) crea in modo differito l'istanza dell'evento dell'oggetto EventRegistrationTokenTable<T>. Passa il campo a livello di classe che conterrà l'istanza della tabella di token a questo metodo. Se il campo è vuoto, il metodo crea la tabella, archivia un riferimento alla tabella nel campo e restituisce un riferimento alla tabella. Se il campo contiene già un riferimento alla tabella di token, il metodo restituisce semplicemente tale riferimento.

Importante

Per garantire la thread safety, il campo che contiene l'istanza dell'evento di EventRegistrationTokenTable<T> deve essere a livello di classe. Se è un campo a livello di classe, il metodo GetOrCreateEventRegistrationTokenTable assicura che tutti i thread ottengano la stessa istanza della tabella quando più thread tentano di creare la tabella di token. Per un determinato evento, tutte le chiamate al metodo GetOrCreateEventRegistrationTokenTable devono utilizzare lo stesso campo a livello di classe.

La chiamata al metodo GetOrCreateEventRegistrationTokenTable nella funzione di accesso remove e nel metodo RaiseEvent (metodo OnRaiseEvent in C#) garantisce che non si verifichi alcuna eccezione se questi metodi vengono chiamati prima dell'aggiunta di qualsiasi delegato del gestore eventi.

Gli altri membri della classe EventRegistrationTokenTable<T> utilizzati nello schema di eventi di Windows Runtime includono:

  • Il metodo AddEventHandler genera un token per il delegato del gestore eventi, archivia il delegato nella tabella, lo aggiunge all'elenco di chiamate e restituisce il token.

  • L'overload del metodo RemoveEventHandler(EventRegistrationToken) rimuove il delegato dalla tabella e dall'elenco chiamate.

    Nota

    I metodi RemoveEventHandler(EventRegistrationToken) e AddEventHandler bloccano la tabella per garantire la thread safety.

  • La proprietà InvocationList restituisce un delegato che include tutti i gestori eventi attualmente registrati per gestire l'evento. Utilizzare questo delegato per generare l'evento o utilizzare i metodi della classe Delegate per richiamare singolarmente i gestori.

    Nota

    Ti consigliamo di seguire lo schema illustrato nell'esempio fornito in precedenza in questo articolo e copiare il delegato in una variabile temporanea prima di richiamarla. Ciò impedisce una race condition in cui il thread rimuove l'ultimo gestore, riducendo il delegato a null prima che un altro thread tenti di richiamare il delegato. I delegati sono immutabili, pertanto la copia è ancora valida.

Posiziona il codice nelle funzioni di accesso nel modo appropriato. Se la thread safety costituisce un problema, devi fornire un blocco personalizzato per il codice.

Per gli utenti di C#: quando scrivi funzioni di accesso a eventi personalizzate nello schema di eventi di Windows Runtime, il compilatore non fornisce le consuete scelte rapide sintattiche. Genera errori se utilizzi il nome dell'evento nel codice.

Utenti di Visual Basic: in .NET Framework un evento è semplicemente un delegato multicast che rappresenta tutti i gestori eventi registrati. Generare l'evento significa semplicemente richiamare il delegato. La sintassi di Visual Basic nasconde in genere le interazioni con il delegato e il compilatore copia il delegato prima di richiamarlo, come descritto nella nota sulla thread safety. Quando crei un evento personalizzato in un componente di Windows Runtime, devi gestire il delegato direttamente. Ciò significa anche che puoi, ad esempio, utilizzare il metodo MulticastDelegate.GetInvocationList per ottenere una matrice che contiene un delegato separato per ogni gestore eventi, se desideri richiamare separatamente i gestori.

Vedere anche

Attività

Procedura: implementare funzioni di accesso a eventi personalizzati (Guida per programmatori C#)

Riferimenti

Eventi (Guida per programmatori C#)

Altre risorse

Eventi (Visual Basic)

Supporto .NET Framework per applicazioni Windows Store e Windows Runtime