Bagikan melalui


Peristiwa kustom dan pengaktif peristiwa di komponen Windows Runtime

Dukungan .NET untuk komponen Windows Runtime memudahkan untuk mendeklarasikan komponen peristiwa dengan menyembunyikan perbedaan antara pola peristiwa Platform Windows Universal (UWP) dan pola peristiwa .NET. Namun, ketika Anda mendeklarasikan pengaktif peristiwa kustom dalam komponen Windows Runtime, Anda harus mengikuti pola yang digunakan dalam UWP.

Mendaftarkan peristiwa

Saat Anda mendaftar untuk menangani peristiwa di UWP, add accessor mengembalikan token. Untuk membatalkan pendaftaran, Anda meneruskan token ini ke aksesor hapus. Ini berarti bahwa tambahkan dan hapus aksesor untuk peristiwa UWP memiliki tanda tangan yang berbeda dari pengaktif yang biasa Anda gunakan.

Untungnya, pengkompilasi Visual Basic dan C# menyederhanakan proses ini: Ketika Anda mendeklarasikan peristiwa dengan aksesor kustom dalam komponen Windows Runtime, pengkompilasi secara otomatis menggunakan pola UWP. Misalnya, Anda mendapatkan kesalahan pengkompilasi jika pengaktif tambahkan tidak mengembalikan token. .NET menyediakan dua jenis untuk mendukung implementasi:

  • Struktur EventRegistrationToken mewakili token.
  • Kelas EventRegistrationTokenTable<T> membuat token dan mempertahankan pemetaan antara token dan penanganan aktivitas. Argumen jenis generik adalah jenis argumen peristiwa. Anda membuat instans kelas ini untuk setiap peristiwa, pertama kali penanganan aktivitas didaftarkan untuk peristiwa tersebut.

Kode berikut untuk peristiwa NumberChanged menunjukkan pola dasar untuk peristiwa UWP. Dalam contoh ini, konstruktor untuk objek argumen peristiwa, NumberChangedEventArgs, mengambil parameter bilangan bulat tunggal yang mewakili nilai numerik yang diubah.

Catatan Ini adalah pola yang sama dengan yang digunakan kompilator untuk peristiwa biasa yang Anda deklarasikan dalam komponen 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

Metode statis (Dibagikan dalam Visual Basic) GetOrCreateEventRegistrationTokenTable membuat instans peristiwa objek EventRegistrationTokenTable<T> dengan malas. Teruskan bidang tingkat kelas yang akan menyimpan instans tabel token ke metode ini. Jika bidang kosong, metode membuat tabel, menyimpan referensi ke tabel di bidang , dan mengembalikan referensi ke tabel. Jika bidang sudah berisi referensi tabel token, metode hanya mengembalikan referensi tersebut.

Penting Untuk memastikan keamanan utas, bidang yang menyimpan instans peristiwa EventRegistrationTokenTable<T> harus merupakan bidang tingkat kelas. Jika ini adalah bidang tingkat kelas, metode GetOrCreateEventRegistrationTokenTable memastikan bahwa ketika beberapa utas mencoba membuat tabel token, semua utas mendapatkan instans tabel yang sama. Untuk peristiwa tertentu, semua panggilan ke metode GetOrCreateEventRegistrationTokenTable harus menggunakan bidang tingkat kelas yang sama.

Memanggil metode GetOrCreateEventRegistrationTokenTable di hapus aksesor dan dalam metode RaiseEvent (metode OnRaiseEvent di C#) memastikan bahwa tidak ada pengecualian yang terjadi jika metode ini dipanggil sebelum delegasi penanganan aktivitas ditambahkan.

Anggota lain dari kelas EventRegistrationTokenTable<T> yang digunakan dalam pola peristiwa UWP meliputi yang berikut ini:

  • Metode AddEventHandler menghasilkan token untuk delegasi penanganan aktivitas, menyimpan delegasi dalam tabel, menambahkannya ke daftar pemanggilan, dan mengembalikan token.

  • Metode RemoveEventHandler(EventRegistrationToken) kelebihan beban menghapus delegasi dari tabel dan dari daftar pemanggilan.

    Catatan Metode AddEventHandler dan RemoveEventHandler(EventRegistrationToken) mengunci tabel untuk membantu memastikan keamanan utas.

  • Properti InvocationList mengembalikan delegasi yang menyertakan semua penanganan aktivitas yang saat ini terdaftar untuk menangani peristiwa. Gunakan delegasi ini untuk menaikkan acara, atau gunakan metode kelas Delegasi untuk memanggil penangan satu per satu.

    Catatan Kami menyarankan agar Anda mengikuti pola yang ditunjukkan dalam contoh yang disediakan sebelumnya dalam artikel ini, dan menyalin delegasi ke variabel sementara sebelum memanggilnya. Ini menghindari kondisi balapan di mana satu utas menghapus handler terakhir, mengurangi delegasi menjadi null tepat sebelum utas lain mencoba memanggil delegasi. Delegasi tidak dapat diubah, sehingga salinan masih valid.

Tempatkan kode Anda sendiri di aksesor sebagaimana mewajarinya. Jika keamanan utas adalah masalah, Anda harus menyediakan penguncian Anda sendiri untuk kode Anda.

Pengguna C#: Saat Anda menulis aksesor peristiwa kustom dalam pola peristiwa UWP, pengompilasi tidak menyediakan pintasan sintaksis yang biasa. Ini menghasilkan kesalahan jika Anda menggunakan nama peristiwa dalam kode Anda.

Pengguna Visual Basic: Di .NET, peristiwa hanyalah delegasi multicast yang mewakili semua penanganan aktivitas terdaftar. Menaikkan acara hanya berarti memanggil delegasi. Sintaks Visual Basic umumnya menyembunyikan interaksi dengan delegasi, dan kompilator menyalin delegasi sebelum memanggilnya, seperti yang dijelaskan dalam catatan tentang keamanan utas. Saat Anda membuat peristiwa kustom di komponen Windows Runtime, Anda harus berurusan dengan delegasi secara langsung. Ini juga berarti Bahwa Anda dapat, misalnya, menggunakan metode MulticastDelegate.GetInvocationList untuk mendapatkan array yang berisi delegasi terpisah untuk setiap penanganan aktivitas, jika Anda ingin memanggil handler secara terpisah.