description | title | ms.date | helpviewer_keywords | ms.assetid | |
---|---|---|---|---|---|
Learn more about: How to: Use Events in C++/CLI | How to: Use Events in C++/CLI | 11/04/2016 |
| fbf452dc-2dd7-4322-adc0-656512d654d1 |
This article shows how to use an interface that declares an event and a function to invoke that event, and the class and event handler that implement the interface.
The following code example adds an event handler, invokes the event—which causes the event handler to write its name to the console—and then removes the event handler.
// mcppv2_events2.cpp// compile with: /clrusingnamespaceSystem; delegate voidDel(int, float); // interface that has an event and a function to invoke the event interface structI { public: event Del ^ E; voidfire(int, float); }; // class that implements the interface event and function ref classEventSource: publicI { public:virtual event Del^ E; virtualvoidfire(int i, float f) { E(i, f); } }; // class that defines the event handler ref classEventReceiver { public:voidHandler(int i , float f) { Console::WriteLine("EventReceiver::Handler"); } }; intmain () { I^ es = gcnew EventSource(); EventReceiver^ er = gcnew EventReceiver(); // hook the handler to the event es->E += gcnew Del(er, &EventReceiver::Handler); // call the event es -> fire(1, 3.14); // unhook the handler from the event es->E -= gcnew Del(er, &EventReceiver::Handler); }
Output
EventReceiver::Handler
The following sample shows how to define an event's behavior when handlers are added or removed, and when an event is raised.
// mcppv2_events6.cpp// compile with: /clrusingnamespaceSystem; public delegate voidMyDel(); public delegate intMyDel2(int, float); ref classEventSource { public: MyDel ^ pE; MyDel2 ^ pE2; event MyDel^ E { voidadd(MyDel^ p) { pE = static_cast<MyDel^> (Delegate::Combine(pE, p)); // cannot refer directly to the event// E = static_cast<MyDel^> (Delegate::Combine(pE, p)); // error } voidremove(MyDel^ p) { pE = static_cast<MyDel^> (Delegate::Remove(pE, p)); } voidraise() { if (pE != nullptr) pE->Invoke(); } } // E event block event MyDel2^ E2 { voidadd(MyDel2^ p2) { pE2 = static_cast<MyDel2^> (Delegate::Combine(pE2, p2)); } voidremove(MyDel2^ p2) { pE2 = static_cast<MyDel2^> (Delegate::Remove(pE2, p2)); } intraise(int i, float f) { if (pE2 != nullptr) { return pE2->Invoke(i, f); } return1; } } // E2 event block }; public ref structEventReceiver { voidH1() { Console::WriteLine("In event handler H1"); } intH2(int i, float f) { Console::WriteLine("In event handler H2 with args {0} and {1}", i.ToString(), f.ToString()); return0; } }; intmain() { EventSource ^ pE = gcnew EventSource; EventReceiver ^ pR = gcnew EventReceiver; // hook event handlers pE->E += gcnew MyDel(pR, &EventReceiver::H1); pE->E2 += gcnew MyDel2(pR, &EventReceiver::H2); // raise events pE->E(); pE->E2::raise(1, 2.2); // call event through scope path// unhook event handlers pE->E -= gcnew MyDel(pR, &EventReceiver::H1); pE->E2 -= gcnew MyDel2(pR, &EventReceiver::H2); // raise events, but no handlers pE->E(); pE->E2::raise(1, 2.5); }
Output
In event handler H1 In event handler H2 with args 1 and 2.2
This sample shows how to override the default access on the add, remove, and raise events methods:
// mcppv2_events3.cpp// compile with: /clr public delegate voidf(int); public ref structE { f ^ _E; public:voidhandler(int i) { System::Console::WriteLine(i); } E() { _E = nullptr; } event f^ Event { voidadd(f ^ d) { _E += d; } private:voidremove(f ^ d) { _E -= d; } protected:voidraise(int i) { if (_E) { _E->Invoke(i); } } } // a member function to access all event methodsstaticvoidGo() { E^ pE = gcnew E; pE->Event += gcnew f(pE, &E::handler); pE->Event(17); // prints 17 pE->Event -= gcnew f(pE, &E::handler); pE->Event(17); // no output } }; intmain() { E::Go(); }
Output
17
An event receiver, or any other client code, can add one or more handlers to an event.
// mcppv2_events4.cpp// compile with: /clrusingnamespaceSystem; #include<stdio.h> delegate voidClickEventHandler(int, double); delegate voidDblClickEventHandler(String^); ref classEventSource { public: event ClickEventHandler^ OnClick; event DblClickEventHandler^ OnDblClick; voidFireEvents() { OnClick(7, 3.14159); OnDblClick("Started"); } }; ref structEventReceiver { public:voidHandler1(int x, double y) { System::Console::Write("Click(x={0},y={1})\n", x, y); }; voidHandler2(String^ s) { System::Console::Write("DblClick(s={0})\n", s); } voidHandler3(String^ s) { System::Console::WriteLine("DblClickAgain(s={0})\n", s); } voidAddHandlers(EventSource^ pES) { pES->OnClick += gcnew ClickEventHandler(this,&EventReceiver::Handler1); pES->OnDblClick += gcnew DblClickEventHandler(this,&EventReceiver::Handler2); pES->OnDblClick += gcnew DblClickEventHandler(this, &EventReceiver::Handler3); } voidRemoveHandlers(EventSource^ pES) { pES->OnClick -= gcnew ClickEventHandler(this, &EventReceiver::Handler1); pES->OnDblClick -= gcnew DblClickEventHandler(this, &EventReceiver::Handler2); pES->OnDblClick -= gcnew DblClickEventHandler(this, &EventReceiver::Handler3); } }; intmain() { EventSource^ pES = gcnew EventSource; EventReceiver^ pER = gcnew EventReceiver; // add handlers pER->AddHandlers(pES); pES->FireEvents(); // remove handlers pER->RemoveHandlers(pES); }
Output
Click(x=7,y=3.14159) DblClick(s=System.Char[]) DblClickAgain(s=System.Char[])
The following sample shows how to define and use static events.
// mcppv2_events7.cpp// compile with: /clrusingnamespaceSystem; public delegate voidMyDel(); public delegate intMyDel2(int, float); ref classEventSource { public:static MyDel ^ psE; static event MyDel2 ^ E2; // event keyword, compiler generates add,// remove, and Invokestatic event MyDel ^ E { staticvoidadd(MyDel ^ p) { psE = static_cast<MyDel^> (Delegate::Combine(psE, p)); } staticvoidremove(MyDel^ p) { psE = static_cast<MyDel^> (Delegate::Remove(psE, p)); } staticvoidraise() { if (psE != nullptr) //psE!=0 -> C2679, use nullptr psE->Invoke(); } } staticintFire_E2(int i, float f) { returnE2(i, f); } }; public ref structEventReceiver { voidH1() { Console::WriteLine("In event handler H1"); } intH2(int i, float f) { Console::WriteLine("In event handler H2 with args {0} and {1}", i.ToString(), f.ToString()); return0; } }; intmain() { EventSource^ pE = gcnew EventSource; EventReceiver^ pR = gcnew EventReceiver; // Called with "this"// hook event handlers pE->E += gcnew MyDel(pR, &EventReceiver::H1); pE->E2 += gcnew MyDel2(pR, &EventReceiver::H2); // raise events pE->E(); pE->Fire_E2(11, 11.11); // unhook event handlers pE->E -= gcnew MyDel(pR, &EventReceiver::H1); pE->E2 -= gcnew MyDel2(pR, &EventReceiver::H2); // Not called with "this"// hook event handler EventSource::E += gcnew MyDel(pR, &EventReceiver::H1); EventSource::E2 += gcnew MyDel2(pR, &EventReceiver::H2); // raise eventsEventSource::E(); EventSource::Fire_E2(22, 22.22); // unhook event handlers EventSource::E -= gcnew MyDel(pR, &EventReceiver::H1); EventSource::E2 -= gcnew MyDel2(pR, &EventReceiver::H2); }
Output
In event handler H1 In event handler H2 with args 11 and 11.11 In event handler H1 In event handler H2 with args 22 and 22.22
This sample implements virtual, managed events in an interface and class:
// mcppv2_events5.cpp// compile with: /clrusingnamespaceSystem; public delegate voidMyDel(); public delegate intMyDel2(int, float); // managed class that has a virtual event ref classIEFace { public:virtual event MyDel ^ E; // declares three accessors (add, remove, and raise) }; // managed interface that has a virtual event public interface structIEFace2 { public: event MyDel2 ^ E2; // declares two accessors (add and remove) }; // implement virtual events ref classEventSource : publicIEFace, publicIEFace2 { public:virtual event MyDel2 ^ E2; voidFire_E() { E(); } intFire_E2(int i, float f) { try { returnE2(i, f); } catch(System::NullReferenceException^) { return0; // no handlers } } }; // class to hold event handlers, the event receiver public ref structEventReceiver { // first handlervoidH1() { Console::WriteLine("In handler H1"); } // second handlerintH2(int i, float f) { Console::WriteLine("In handler H2 with args {0} and {1}", i.ToString(), f.ToString()); return0; } }; intmain() { EventSource ^ pE = gcnew EventSource; EventReceiver ^ pR = gcnew EventReceiver; // add event handlers pE->E += gcnew MyDel(pR, &EventReceiver::H1); pE->E2 += gcnew MyDel2(pR, &EventReceiver::H2); // raise events pE->Fire_E(); pE->Fire_E2(1, 2.2); // remove event handlers pE->E -= gcnew MyDel(pR, &EventReceiver::H1); pE->E2 -= gcnew MyDel2(pR, &EventReceiver::H2); // raise events, but no handlers; so, no effect pE->Fire_E(); pE->Fire_E2(1, 2.5); }
Output
In handler H1 In handler H2 with args 1 and 2.2
A simple event cannot be specified to override or hide a base class event. You must define all of the event's accessor functions, and then specify the new
or override
keyword on each accessor function.
// mcppv2_events5_a.cpp// compile with: /clr /c delegate voidDel(); ref structA { virtual event Del ^E; virtual event Del ^E2; }; ref structB : A { virtual event Del ^E override; // C3797virtual event Del ^E2new; // C3797 }; ref structC : B { virtual event Del ^E { // OKvoidraise() override {} voidadd(Del ^) override {} voidremove(Del^) override {} } virtual event Del ^E2 { // OKvoidraise() new {} voidadd(Del ^) new {} voidremove(Del^) new {} } };
The following sample shows how to implement an abstract event.
// mcppv2_events10.cpp// compile with: /clr /W1usingnamespaceSystem; public delegate voidDel(); public delegate voidDel2(String^ s); interface structIEvent { public:// in this case, no raised method is defined event Del^ Event1; event Del2^ Event2 { public:voidadd(Del2^ _d); voidremove(Del2^ _d); voidraise(String^ s); } voidfire(); }; ref classEventSource: publicIEvent { public:virtual event Del^ Event1; event Del2^ Event2 { virtualvoidadd(Del2^ _d) { d = safe_cast<Del2^>(System::Delegate::Combine(d, _d)); } virtualvoidremove(Del2^ _d) { d = safe_cast<Del2^>(System::Delegate::Remove(d, _d)); } virtualvoidraise(String^ s) { if (d) { d->Invoke(s); } } } virtualvoidfire() { returnEvent1(); } private: Del2^ d; }; ref classEventReceiver { public:voidfunc() { Console::WriteLine("hi"); } voidfunc(String^ str) { Console::WriteLine(str); } }; intmain () { IEvent^ es = gcnew EventSource; EventReceiver^ er = gcnew EventReceiver; es->Event1 += gcnew Del(er, &EventReceiver::func); es->Event2 += gcnew Del2(er, &EventReceiver::func); es->fire(); es->Event2("hello from Event2"); es->Event1 -= gcnew Del(er, &EventReceiver::func); es->Event2 -= gcnew Del2(er, &EventReceiver::func); es->Event2("hello from Event2"); }
Output
hi hello from Event2
An event and event handler can be defined in one assembly, and consumed by another assembly.
// mcppv2_events8.cpp// compile with: /LD /clrusingnamespaceSystem; public delegate voidDel(String^ s); public ref classSource { public: event Del^ Event; voidFire(String^ s) { Event(s); } };
This client code consumes the event:
// mcppv2_events9.cpp// compile with: /clr #using"mcppv2_events8.dll"usingnamespaceSystem; ref classReceiver { public:voidHandler(String^ s) { Console::WriteLine(s); } }; intmain() { Source^ src = gcnew Source; Receiver^ rc1 = gcnew Receiver; Receiver^ rc2 = gcnew Receiver; src -> Event += gcnew Del(rc1, &Receiver::Handler); src -> Event += gcnew Del(rc2, &Receiver::Handler); src->Fire("hello"); src -> Event -= gcnew Del(rc1, &Receiver::Handler); src -> Event -= gcnew Del(rc2, &Receiver::Handler); }
Output
hello hello