Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers. In a typical xtd Windows Forms application, you subscribe to events raised by controls such as buttons and list boxes. For more information, see How to subscribe to and unsubscribe from events.
Events have the following properties:
void handle_custom_event(object& sender, custom_event_args& e) {
}
publisher.raise_custom_event += {*this, &subscriber::handle_custom_event};
or
publisher.raise_custom_event += custom_event_handler(*this, &my_class::handle_custom_event);
To subscribe to events by using a lambda expression
If you don't have to unsubscribe from an event later, you can use the addition assignment operator += to attach a lambda expression as an event handler. In the following example, assume that an object named publisher has an event named *raise_custom_event and that a custom_event_args class has also been defined to carry some kind of specialized event information. Note that the subscriber class needs a reference to publisher in order to subscribe to its events.
publisher.raise_custom_event += [](object& sender, custom_event_args& e) {
xtd::string s = sender.to_string() + " " + e.to_string();
console::write_line(s);
};
You cannot easily unsubscribe from an event if you used a lambda expression to subscribe to it. To unsubscribe in this scenario, go back to the code where you subscribe to the event, store the anonymous function in a delegate variable, and then add the delegate to the event. We recommend that you don't use lambda expression to subscribe to events if you have to unsubscribe from the event at some later point in your code. For more information about anonymous functions, see lambda expression.
UnsubscribingTo prevent your event handler from being invoked when the event is raised, unsubscribe from the event. In order to prevent crash, you should unsubscribe from events before you destroy a subscriber object. Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler.
To unsubscribe from an eventUse the subtraction assignment operator -= to unsubscribe from an event:
publisher.raise_custom_event -= {*this, &subscriber::handle_custom_event};
or
publisher.raise_custom_event -= custom_event_handler(*this, &subscriber::handle_custom_event);
When all subscribers have unsubscribed from an event, the event instance in the publisher class is set to empty.
How to publish events that conform to xtd GuidelinesThe following procedure demonstrates how to add events that follow the standard xtd pattern to your classes and structs. All events in the xtd framework are based on the xtd::event_handler delegate, which is defined as follows:
template<typename event_args_t = const xtd::event_args&>
using generic_event_handler = xtd::delegate<void(xtd::object& sender, event_args_t e)>;
and
using event_handler = xtd::generic_event_handler<>;
Although events in classes that you define can be based on any valid delegate type, even delegates that return a value, it is generally recommended that you base your events on the xtd pattern by using xtd::event_handler, as shown in the following example. The name event_handler can lead to a bit of confusion as it doesn't actually handle the event. The xtd::event_handler, and generic xtd::generic_event_handler<event_args_t>
are delegate types. A method or lambda expression whose signature matches the delegate definition is the event handler and will be invoked when the event is raised.
struct custom_event_args : xtd::event_args {
custom_event_args() = default;
custom_event_args(const xtd::string& message) : message_(message) {}
xtd::string message;
};
generic_event_handler<event_args_t>
.) Declare a delegate in your publishing class. Give it a name that ends with event_handler. The second parameter specifies your custom event_args type.using custom_event_handler = xtd::delegate<void(xtd::object& sender, custom_event_args& args)>;
a. If you have no custom event_args class, your event type will be the non-generic event_handler delegate. You do not have to declare the delegate because it is already declared in the xtd namespace that is included when you create your xtd project. Add the following code to your publisher class.
xtd::event<publisher, xtd::event_handler> raise_custom_event;
where publisher is the class name that contains the raise_custom_event event.
b. If you are using the non-generic version of event_handler and you have a custom class derived from event_args, declare your event inside your publishing class and use your delegate from step 2 as the type.
xtd::event<publisher, custom_event_handler> raise_custom_event;
Where publisher is the class name that contains the raise_custom_event event.
c. If you are using the generic version, you do not need a custom delegate. Instead, in your publishing class, you specify your event type as generic_event_handler<custom_event_args>
, substituting the name of your own class between the angle brackets.
xtd::event<publisher, generic_event_handler<custom_event_args&>> raise_custom_event;
Where publisher is the class name that contains the raise_custom_event event.
ExampleThe following example demonstrates the previous steps by using a custom event_args class and genric_event_handler<event_args_t>
as the event type.
#include <xtd/xtd>
using namespace xtd;
struct custom_event_args : xtd::event_args {
custom_event_args() = default;
custom_event_args(const xtd::string& message) : message_(message) {}
xtd::string message;
};
class publisher : public object {
public:
event<publisher, generic_event_handler<custom_event_args&>> raise_custom_event;
void do_something() {
custom_event_args event_args("Event triggered");
on_raise_custom_event(event_args);
}
protected:
virtual void on_raise_custom_event(custom_event_args& e) {
event<publisher, generic_event_handler<custom_event_args&>> raise_event = raise_custom_event;
if (!raise_event.is_empty()) {
e.message(string::format("{} at {}", e.message(), date_time::now()));
raise_event(*this, e);
}
}
};
class subscriber : public object {
public:
subscriber(string id, publisher& pub) : id_(id) {
pub.raise_custom_event += {*this, &subscriber::handle_custom_event};
}
void handle_custom_event(object& sender, custom_event_args& e) {
console::write_line(string::format("{} received this message: {}", id_, e.message()));
}
private:
string id_;
};
class program {
public:
static auto main() {
publisher pub;
subscriber sub1("sub1", pub);
subscriber sub2("sub2", pub);
pub.do_something();
}
};
startup_(program::main);
See also
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4