The EventHandler feature is a wrapper around ScriptInvoker that mimics the C# EventHandler concept by introducing subscriber functions that receive a sender object and args of a variable type TEventArgs.
The class CF_EventArgs transports all additional event data besides the sender object and is the base class that all non-primitive types of event args should inherit from. The constant CF_EventArgs.Empty can be used when sending an event that has no data.
class MyCustomEventArgs : CF_EventArgs
{
int someValue;
float moreData;
};The class CF_EventHandler is a substitute for CF_EventHandlerT<CF_EventArgs> and will be the correct choice for most use-cases. Please see the CF_EventHandlerT<TEventArgs> section for more information.
The class CF_EventHandlerT<TEventArgs>must be instantiated to declare a subscribable event. The template argument TEventArgs can be used to send a single primitive as event args or to restrict what kind of CF_EventArgs inherited type is accepted for invoking the event.
class CF_EventHandlerT_SetupDemo
{
static ref CF_EventHandlerT<float> MyStaticPrimtiveArgsEvent = new CF_EventHandlerT<float>();
ref CF_EventHandlerT<MyCustomEventArgs> MyInstanceCustomArgsEvent;
};After having setup an EventHandler instance, you can invoke the event by calling the Invoke(Class sender = NULL, TEventArgs args = NULL) method on it.
This will cause all registered subscribers to be executed in the order that they were registered in.
A common value for the sender parameter will be the object instance that called the invoke.
class CF_EventHandlerT_InvokeDemo
{
ref CF_EventHandlerT<CF_EventArgs> MyEvent;
void InvokeEvent()
{
MyEvent.Invoke(this, CF_EventArgs.Empty);
//Sender only param alternative - args will be NULL
MyEvent.Invoke(this);
//No params alternative - sender will be NULL, args will be NULL
MyEvent.Invoke();
}
};Functions that shall be executed when the event is invoked can be registered as subscribers by calling the AddSubscriber(ScriptCaller subscriber) method on the EventHandler instance.
You can register global and static functions as well as instance methods.
void MyGlobalPrimtiveHandler(Class sender, float args) {} //for CF_EventHandlerT<float>
class CF_EventHandlerT_SubscribeDemo
{
static void MySubscriberStaticFunction(Class sender, MyCustomEventArgs args) {} //for CF_EventHandlerT<MyCustomEventArgs>
void MySubscriberMethod(Class sender, CF_EventArgs args) {} //for CF_EventHandlerT<CF_EventArgs> aka CF_EventHandler
};
void RegisterSubscribersDemo()
{
//Global function
new CF_EventHandlerT<float>().AddSubscriber(ScriptCaller.Create(MyGlobalPrimtiveHandler));
//Static function
new CF_EventHandlerT<MyCustomEventArgs>().AddSubscriber(ScriptCaller.Create(CF_EventHandlerT_SubscribeDemo.MySubscriberStaticFunction));
//Instance method
auto instance = new CF_EventHandlerT_DemoSubscribe(); //Must be kept alive or the subscriber function will be invalid.
new CF_EventHandler().AddSubscriber(ScriptCaller.Create(instance.MySubscriberMethod));
}You can also subscribe a single function to multiple EventHandlers that have different TEventArgs if you use CF_EventArgs as args type and do a runtime type check.
void HandleCustomArgsAlternative(Class sender, CF_EventArgs args)
{
MyCustomEventArgs customArgs;
if(Class.CastTo(customArgs, args))
{
//do stuff here
}
}Similar to how C# handles it, the subscribing function can omit the args or both parameters and still be invokable on the same kind of event.
void HandleSomethingVariant1(Class sender) {}
void HandleSomethingVariant2() {}If the subscriber function is global or static you may make use of custom attributes as decatorators above the functions itself.
There are two types of attributes: CF_EventSubscriber for subscribing up to 9 EventHandler instances and CF_MultiEventSubscriber if you need more.
//You can have them in one line
[CF_EventSubscriber(ScriptCaller.Create(TestGlobalEventSubscriber), Event1, Event2)]
void TestGlobalEventSubscriber()
{
Print("TestGlobalEventSubscriber");
}
class StaticWrapper
{
//Or across multiple lines.
//Only the section opening [ and closing ] must be on the same line as the attribute opening ( and closing )
[CF_MultiEventSubscriber(ScriptCaller.Create(StaticWrapper.TestMultiEventSubscriber),
{
Event1,
Event2,
...
EventN
})]
static void TestMultiEventSubscriber()
{
Print("TestMultiEventSubscriber");
}
}