Freigeben über


Benutzerdefinierte Ereignisse und Ereignisaccessoren der Komponenten für Windows-Runtime

.NET Framework-Unterstützung für Windows-Runtime erleichtert die Deklaration von Ereignissen in Windows-Runtime-Komponenten durch Ausblenden der Unterschiede zwischen dem Windows-Runtime- und dem .NET Framework-Ereignismuster. Wenn Sie jedoch benutzerdefinierte Ereignisaccessoren in einer Windows-Runtime-Komponente deklarieren, ist dem Windows-Runtime-Muster zu folgen.

Bei der Registrierung zur Behandlung von Ereignissen in Windows-Runtime, gibt der add-Accessor ein Token zurück. Soll die Registrierung aufgehoben werden, übergeben Sie das Token an den remove-Accessor. Folglich haben die add- und remove-Accessoren für Windows-Runtime-Ereignisse andere Signaturen als die Accessoren, die Sie kennen.

Mit dem Visual Basic- und C#-Compiler lässt sich dieser Prozess vereinfachen. Bei der Deklaration eines Ereignisses mit benutzerdefinierten Accessoren in einer Windows-Runtime-Komponente verwenden die Compiler automatisch das Windows-Runtime-Muster. Gibt der add-Accessor beispielsweise kein Token zurück, kommt es zu einem Compilerfehler. Diese Implementierung wird im .NET Framework zweifach unterstützt:

  • Die EventRegistrationToken-Struktur bildet das Token.

  • Die EventRegistrationTokenTable<T>-Klasse erstellt Token und bildet eine Zuordnung zwischen Token und Ereignishandlern. Das Argument für den generischen Typ ist der Ereignisargumenttyp. Beim erstmaligen Registrieren eines Ereignishandlers für dieses Ereignis erstellen Sie für jedes Ereignis eine Instanz dieser Klasse.

Der folgende Code für das NumberChanged-Ereignis zeigt das grundlegende Muster für Windows-Runtime-Ereignisse. Bei diesem Beispiel nimmt der Konstruktor für das Ereignisargumentobjekt, d. h. NumberChangedEventArgs, einen einzelnen ganzzahligen Parameter an, der den geänderten numerischen Wert darstellt.

Hinweis

Dies ist das gleiche Muster, das die Compiler für normale Ereignisse nutzen, die Sie in einer Windows-Runtime-Komponente deklarieren.

    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

Mit der static-Methode (in Visual Basic Shared) GetOrCreateEventRegistrationTokenTable wird die Ereignisinstanz des EventRegistrationTokenTable<T>-Objekts erstellt. Übergeben Sie das Feld auf Klassenebene, das die Instanz der Tokentabelle enthält, an diese Methode. Wenn das Feld leer ist, erstellt die Methode die Tabelle, speichert im Feld einen Verweis darauf und gibt einen Verweis auf die Tabelle zurück. Enthält das Feld bereits einen Verweis auf eine Tokentabelle, gibt die Methode einfach diesen zurück.

Wichtig

Um Threadsicherheit zu gewährleisten, muss das Feld, in dem die Instanz des Ereignisses von EventRegistrationTokenTable<T> enthalten ist, ein Feld auf Klassenebene sein. Handelt es sich um ein Feld auf Klassenebene, wird mithilfe der GetOrCreateEventRegistrationTokenTable-Methode sichergestellt, dass, wenn mehrere Threads versuchen, die Tokentabelle zu erstellen, alle Threads die gleiche Instanz der Tabelle abrufen. Bei einem bestimmten Ereignis müssen alle Aufrufe der GetOrCreateEventRegistrationTokenTable-Methode das gleiche Feld auf Klassenebene verwenden.

Durch Aufrufen der GetOrCreateEventRegistrationTokenTable-Methode im remove-Accessor und in der RaiseEvent-Methode (in C# OnRaiseEvent-Methode) wird dafür gesorgt, dass keine Ausnahmen auftreten, wenn die Methoden vor dem Hinzufügen von Ereignishandlerdelegaten aufgerufen werden.

Die anderen Mitglieder der EventRegistrationTokenTable<T>-Klasse aus dem Windows-Runtime-Ereignismuster sind folgende:

  • Die AddEventHandler-Methode erstellt ein Token für den Ereignishandlerdelegaten, speichert diesen in der Tabelle, fügt ihn der Aufrufliste hinzu und gibt das Token zurück.

  • Die RemoveEventHandler(EventRegistrationToken)-Methodenüberladung entfernt den Delegaten aus der Tabelle und der Aufrufliste.

    Hinweis

    Die Methoden AddEventHandler und RemoveEventHandler(EventRegistrationToken) sperren zwecks Threadsicherheit die Tabelle.

  • Die InvocationList-Eigenschaft gibt einen Delegaten zurück, der alle Ereignishandler enthält, die derzeit zur Behandlung des Ereignisses registriert sind. Lösen Sie mit diesem Delegaten das Ereignis aus, oder rufen Sie mit den Methoden der Delegate-Klasse die Handler einzeln auf.

    Hinweis

    Es wird empfohlen, dem Muster aus dem Beispiel in diesem Artikel zu folgen und den Delegaten vor dem Aufrufen in eine temporäre Variable zu kopieren. So lässt sich eine Racebedingung vermeiden, bei der ein Thread den letzten Handler entfernt und der Delegat auf null reduziert wird, bevor ein anderer Thread versucht, ihn aufzurufen. Delegaten sind unveränderlich. Die Kopie gilt also auch weiterhin.

Platzieren Sie Ihren Code wie erforderlich in den Accessoren. Bei problematischer Threadsicherheit versehen Sie Ihren Code mit einer eigenen Sperre.

C#-Benutzer: Wenn Sie benutzerdefinierte Ereignisaccessoren in das Windows-Runtime-Ereignismuster schreiben, stellt der Compiler nicht die üblichen syntaktischen Verknüpfungen zur Verfügung. Wird der Name des Ereignisses im Code verwendet, kommt es zu Fehlern.

Visual Basic-Benutzer: In .NET Framework ist ein Ereignis nur ein Multicastdelegat zur Darstellung aller registrierten Ereignishandler. Wird das Ereignis ausgelöst, wird lediglich der Delegat aufgerufen. In der Visual Basic-Syntax werden die Interaktionen mit dem Delegaten in der Regel ausgeblendet, und der Compiler kopiert den Delegaten, bevor er ihn aufruft, wie in der Anmerkung zur Threadsicherheit beschrieben. Wird ein benutzerdefiniertes Ereignis in einer Windows-Runtime-Komponente erstellt, muss der Delegat direkt behandelt werden. Bei einem Array, das für jeden Ereignishandler einen eigenen Delegaten enthält, bedeutet dies auch, dass Sie das Array mit der MulticastDelegate.GetInvocationList-Methode abrufen können, um die Handler separat aufzurufen.

Siehe auch

Aufgaben

Gewusst wie: Implementieren benutzerdefinierter Ereignisaccessoren (C#-Programmierhandbuch)

Referenz

Ereignisse (C#-Programmierhandbuch)

Weitere Ressourcen

Ereignisse (Visual Basic)

.NET Framework-Unterstützung für Windows Store-Apps und Windows-Runtime