Peristiwa (C++/CX)
Jenis Windows Runtime dapat mendeklarasikan (yaitu, menerbitkan) peristiwa, dan kode klien dalam komponen yang sama atau di komponen lain dapat berlangganan peristiwa tersebut dengan mengaitkan metode yang disebut penanganan aktivitas dengan peristiwa. Beberapa penanganan aktivitas dapat dikaitkan dengan satu peristiwa. Ketika objek penerbitan menaikkan peristiwa, itu menyebabkan semua penanganan aktivitas dipanggil. Dengan cara ini, kelas berlangganan dapat melakukan tindakan kustom apa pun yang sesuai ketika penerbit menaikkan peristiwa. Kejadian memiliki jenis delegasi yang menentukan tanda tangan yang harus dimiliki semua penanganan aktivitas untuk berlangganan peristiwa.
Mengkonsumsi peristiwa di komponen Windows
Banyak komponen dalam windows Runtime mengekspos peristiwa. Misalnya, objek LightSensor menembakkan peristiwa ReadingChanged ketika sensor melaporkan nilai luminescence baru. Ketika Anda menggunakan objek LightSensor dalam program Anda, Anda dapat menentukan metode yang akan dipanggil ketika peristiwa ReadingChanged ditembakkan. Metode ini dapat melakukan apa pun yang Anda inginkan; satu-satunya persyaratan adalah bahwa tanda tangannya harus cocok dengan tanda tangan delegasi yang dipanggil. Untuk informasi selengkapnya tentang cara membuat penanganan aktivitas delegasi dan berlangganan acara, lihat Delegasi.
Membuat peristiwa kustom
Deklarasi
Anda dapat mendeklarasikan peristiwa di kelas ref atau antarmuka, dan dapat memiliki aksesibilitas publik, internal (publik/privat), dilindungi publik, dilindungi, dilindungi privat, atau privat. Saat Anda mendeklarasikan peristiwa, secara internal pengkompilasi membuat objek yang mengekspos dua metode pengakses: tambahkan dan hapus. Saat berlangganan objek mendaftarkan penanganan aktivitas, objek peristiwa menyimpannya dalam koleksi. Saat peristiwa diaktifkan, objek peristiwa memanggil semua handler dalam daftarnya secara bergantian. Peristiwa sepele—seperti yang ada dalam contoh berikut—memiliki penyimpanan backing implisit serta metode implisit add
dan remove
aksesor. Anda juga dapat menentukan aksesor Anda sendiri, dengan cara yang sama seperti Anda dapat menentukan kustom get
dan set
aksesor pada properti. Kelas penerapan tidak dapat menelusuri daftar pelanggan peristiwa secara manual dalam peristiwa sepele.
Contoh berikut menunjukkan cara mendeklarasikan dan mengaktifkan peristiwa. Perhatikan bahwa peristiwa memiliki jenis delegasi dan dideklarasikan dengan menggunakan simbol "^".
namespace EventTest
{
ref class Class1;
public delegate void SomethingHappenedEventHandler(Class1^ sender, Platform::String^ s);
public ref class Class1 sealed
{
public:
Class1(){}
event SomethingHappenedEventHandler^ SomethingHappened;
void DoSomething()
{
//Do something....
// ...then fire the event:
SomethingHappened(this, L"Something happened.");
}
};
}
Penggunaan
Contoh berikut menunjukkan bagaimana kelas berlangganan menggunakan +=
operator untuk berlangganan peristiwa, dan menyediakan penanganan aktivitas untuk dipanggil saat peristiwa diaktifkan. Perhatikan bahwa fungsi yang disediakan cocok dengan tanda tangan delegasi yang ditentukan di sisi penerbit di EventTest
namespace layanan.
namespace EventClient
{
using namespace EventTest;
namespace PC = Platform::Collections; //#include <collection.h>
public ref class Subscriber sealed
{
public:
Subscriber() : eventCount(0)
{
// Instantiate the class that publishes the event.
publisher= ref new EventTest::Class1();
// Subscribe to the event and provide a handler function.
publisher->SomethingHappened +=
ref new EventTest::SomethingHappenedEventHandler(
this,
&Subscriber::MyEventHandler);
eventLog = ref new PC::Map<int, Platform::String^>();
}
void SomeMethod()
{
publisher->DoSomething();
}
void MyEventHandler(EventTest::Class1^ mc, Platform::String^ msg)
{
// Our custom action: log the event.
eventLog->Insert(eventCount, msg);
eventCount++;
}
private:
PC::Map<int, Platform::String^>^ eventLog;
int eventCount;
EventTest::Class1^ publisher;
};
}
Peringatan
Secara umum, lebih baik menggunakan fungsi bernama, daripada lambda, untuk penanganan aktivitas kecuali Anda berhati-hati untuk menghindari referensi melingkar. Fungsi bernama menangkap penunjuk "ini" dengan referensi lemah, sedangkan lambda menangkapnya dengan referensi yang kuat dan membuat referensi melingkar. Untuk informasi selengkapnya, lihat Referensi lemah dan siklus pemecah (C++/CX).
Tambahkan dan hapus metode kustom
Secara internal, peristiwa memiliki metode tambahkan, metode hapus, dan metode kenaikan. Saat kode klien berlangganan peristiwa, metode tambahkan dipanggil dan delegasi yang diteruskan ditambahkan ke daftar pemanggilan peristiwa. Kelas penerbitan memanggil peristiwa, itu menyebabkan metode raise() dipanggil, dan setiap delegasi dalam daftar dipanggil secara bergantian. Pelanggan dapat menghapus dirinya sendiri dari daftar delegasi, yang menyebabkan metode penghapusan peristiwa dipanggil. Pengkompilasi menyediakan versi default metode ini jika Anda tidak menentukannya dalam kode Anda; ini dikenal sebagai peristiwa sepele. Dalam banyak kasus, peristiwa sepele adalah semua yang diperlukan.
Anda dapat menentukan metode penambahan, penghapusan, dan penambahan kustom untuk suatu peristiwa jika Anda harus melakukan logika kustom sebagai respons terhadap penambahan atau penghapusan pelanggan. Misalnya, jika Anda memiliki objek mahal yang hanya diperlukan untuk pelaporan peristiwa, Anda dapat dengan malas menunda pembuatan objek sampai klien benar-benar berlangganan acara.
Contoh berikutnya menunjukkan cara menambahkan, menghapus, dan menaikkan metode kustom ke peristiwa:
namespace EventTest2
{
ref class Class1;
public delegate void SomethingHappenedEventHandler(Class1^ sender, Platform::String^ msg);
public ref class Class1 sealed
{
public:
Class1(){}
event SomethingHappenedEventHandler^ SomethingHappened;
void DoSomething(){/*...*/}
void MethodThatFires()
{
// Fire before doing something...
BeforeSomethingHappens(this, "Something's going to happen.");
DoSomething();
// ...then fire after doing something...
SomethingHappened(this, L"Something happened.");
}
event SomethingHappenedEventHandler^ _InternalHandler;
event SomethingHappenedEventHandler^ BeforeSomethingHappens
{
Windows::Foundation::EventRegistrationToken add(SomethingHappenedEventHandler^ handler)
{
// Add custom logic here:
//....
return _InternalHandler += handler;
}
void remove(Windows::Foundation::EventRegistrationToken token)
{
// Add custom logic here:
//....
_InternalHandler -= token;
}
void raise(Class1^ sender, Platform::String^ str)
{
// Add custom logic here:
//....
return _InternalHandler(sender, str);
}
}
};
}
Menghapus penanganan aktivitas dari sisi pelanggan
Dalam beberapa kasus yang jarang terjadi, Anda mungkin ingin menghapus penanganan aktivitas untuk peristiwa yang sebelumnya Anda berlangganan. Misalnya, Anda mungkin ingin menggantinya dengan penanganan aktivitas lain atau Anda mungkin ingin menghapus beberapa sumber daya yang dipegang olehnya. Untuk menghapus handler, Anda harus menyimpan EventRegistrationToken yang dikembalikan dari +=
operasi. Anda kemudian dapat menggunakan -=
operator pada token untuk menghapus penanganan aktivitas. Namun, handler asli masih dapat dipanggil bahkan setelah dihapus. Misalnya, kondisi balapan mungkin muncul ketika sumber peristiwa mendapatkan daftar handler dan mulai memanggilnya. Jika penanganan aktivitas dihapus saat ini terjadi, daftar menjadi kedaluarsa. Jadi, jika Anda ingin menghapus penanganan aktivitas, buat bendera anggota. Atur jika peristiwa dihapus, lalu di penanganan aktivitas, periksa bendera, dan segera kembali jika diatur. Contoh berikutnya menunjukkan pola dasar.
namespace EventClient2
{
using namespace EventTest2;
ref class Subscriber2 sealed
{
private:
bool handlerIsActive;
Platform::String^ lastMessage;
void TestMethod()
{
Class1^ c1 = ref new Class1();
handlerIsActive = true;
Windows::Foundation::EventRegistrationToken cookie =
c1->SomethingHappened +=
ref new EventTest2::SomethingHappenedEventHandler(this, &Subscriber2::MyEventHandler);
c1->DoSomething();
// Do some other work�..then remove the event handler and set the flag.
handlerIsActive = false;
c1->SomethingHappened -= cookie;
}
void MyEventHandler(Class1^ mc, Platform::String^ msg)
{
if (!handlerIsActive)
return;
lastMessage = msg;
}
};
}
Keterangan
Beberapa handler dapat dikaitkan dengan peristiwa yang sama. Sumber kejadian secara berurutan memanggil semua penanganan aktivitas dari utas yang sama. Jika penerima peristiwa memblokir dalam metode penanganan aktivitas, itu memblokir sumber peristiwa agar tidak memanggil penanganan aktivitas lain untuk peristiwa ini.
Urutan di mana sumber peristiwa memanggil penanganan aktivitas pada penerima peristiwa tidak dijamin dan mungkin berbeda dari panggilan ke panggilan.
Lihat juga
Sistem Jenis
Delegasi
Referensi Bahasa C++/CX
Referensi Namespace