Is it possible to use Custom EventArgs with SystemEvents? - c#

My first post, apologies if this has been answered already - I have searched and searched but have not found any specifics on using Custom EventArgs with existing SystemEvents.
I am trying to take advantage of the SystemEvents.PowerModeChanged type events but would like to use my own Custom EventArgs instead of the standard PowerModeChangedEventArgs. My approach was to create a class called CustomPowerModeChangedEventArgs which inherits from PowerModeChangedEventArgs and use these instead but I don't know how to tell the PowerModeChangedEventHandler to use these new CustomEvent args. My code is as follows:
//Define the custom args which inherit from the PowerModeChangedEventArgs
public class CustomPowerModeChangedEventArgs : PowerModeChangedEventArgs
{
public string batterylevel { get; set; }
}
//event raising method with CustomArgs instead of the PowerModeChangedEventArgs
protected virtual void PowerModeChanged(object source, CustomPowerModeChangedEventArgs e)
{
}
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(PowerModeChanged);
The problem is with the PowerModeEventChangedHandler not accepting the method PowerModeChanged with the CustomArgs. Had it been a generic eventhandler I could define the args like...
public event EventHandler<CustomPowerModeChangedEventArgs> PowerModeCHanged;
...but I can't fathom how to achieve similar with a non generic event handler. I have a suspicion that it might be possible to send the new custom args to the handler using lambda expressions but I'm really not sure about this - maybe I need to define a whole new EventChangedHandler? Any advice would be greatly appreciated.

No, you don't get to decide what parameters the event handler has. Bear in mind that there's already code in the system which is going to call your event handler... how would you expect it to construct an instance of your CustomPowerModeChangedEventArgs?
If the event had been declared using EventHandler<T>, that still wouldn't have helped you - the code calling the event handler has already been written, and it's going to pass in a PowerModeChangedEventArgs that it constructs, not an instance of your type.
Now you could declare your own event using your custom event-args, and then hook into the SystemEvents so that you raise your own event (with an instance of your own event-args, however you decide to construct that) when the system event is raised... but you shouldn't expect to be able to add an event handler which requires information the event raiser (in this case the system) isn't aware of.

Related

Create a special dictionary<T, EventDelegate<T>> with generic delegate EventDelegate<T>(T e) where T : GameEventBase

I have a game with many classes that need to listen to events. But under certain circumstances, those classes are destroyed or disabled. When that happens, I need to remove their listening methods from the events manager delegate table.
I don't want to modify the EventsManager and I would like to each class that adds any events to it to know which events it added.
I'm currently using something like this do add and remove the events in each class:
void AddEventsListeners() {
EventsManager.AddListener<OnClickDown>(OnClickDownHandler);
EventsManager.AddListener<OnClickUp>(OnClickUpHandler);
EventsManager.AddListener<OnClick>(OnClickHandler);
}
void RemoveEventsListeners() {
EventsManager.RemoveListener<OnClickDown>(OnClickDownHandler);
EventsManager.RemoveListener<OnClickUp>(OnClickUpHandler);
EventsManager.RemoveListener<OnClick>(OnClickHandler);
}
Those OnClick are all derived from GameEventBase, and the OnClickHandler are methods declared as
void OnClickDown(OnClickHandler e) {}
to match the delegate that is used in the EventsManager, which is declared as
delegate void EventDelegate<T>(T e) where T : GameEventBase;
I want to be able to fill a special hash table named, say, events, that has keyvalue pairs like
<T, EventDelegate<T>> where T: GameEventBase
That is, I want to be able to do events.add(OnClick, OnClickHandler), where OnClickHandler is declared as
OnClickHandler(OnClick e) {}
And I want adding to fail if OnClickHandler where defined, for example, as
OnClickHandler(OtherGameEventBaseDerivedEvent e) {}
That requirement translates to me wanting type safety in that special dictionary.
One of my attempts involved not a dictionary, but a way to decide which method to call, between the AddListener and RemoveListener
I didn't like it because it introduces a parameter to the method and the code reads really weird with it. It does work, and does reduce the repetition, but is too ugly.
I create a AddOrRemoveAllListeners(AddOrRemove addOrRemove), which I populated with calls to AddOrRemoveListener for each event.
Now all I had to do is AddOrRemoveAllListeners(AddOrRemove.Remove) or AddOrRemoveAllListeners(AddOrRemove.Add), to add or remove my events.
enum AddOrRemove {
Remove,
Add
}
void AddOrRemoveListener<T>(EventsManager.EventDelegate<T> del, AddOrRemove addOrRemove)
where T : GameEventBase {
switch (addOrRemove) {
case AddOrRemove.Remove:
EvMan.RemoveListener<T>(del);
break;
case AddOrRemove.Add:
EvMan.AddListener<T>(del);
break;
}
}
Another attempt involved creating the type
class EventsDictionary<T> : Dictionary<T, EventsManager.EventDelegate<T>> where T : GameEventBase { }
And using it like this:
EventsDictionary<GameEventBase> events = new MyCustomDictionary<GameEventBase>();
void AddEventHandlerPairToEventsDictionary<T>(T e, EventsManager.EventDelegate<T> handler) where T : GameEventBase {
if (!events.ContainsKey(e)) {
events.Add(e, handler);
}
}
But the events.Add(e, handler) fails and forces me to declare the handler as
EventsManager.EventDelegate<GameEventBase>
instead of
EventsManager.EventDelegate<T>
If I do that, I could add keyvalue pairs that don't make sense in that events type, i.e., I lose the event handling type safety.
I want to have such a structure because I don't like all those repetitions. It would be really bad if someone forgot to remove an event in the RemoveEventsListeners().
Having such a dictionary, I could use a foreach loop to add/remove the handlers to the EventsManager, which would be really nice.
As for performance, this is for a game and it needs to have good performance. Those adding/removing of events can happen a lot (sometimes hundreds of times per frame) because a lot of objects are destroyed (can't leave null handlers in the EventsManager) or disabled (need to stop listening to everything until enabled again) all the time. This means reflection and lots of casting/boxing or anything that creates lots of garbage collected objects is out.
I'm, of course, open to suggestions as to other ways to approach this.
Thanks for your assistance!
I'm attaching the relevant parts of the EventsManager being used (The RemoveListener() is analogous to the AddListener). The GameEventBase is just an empty shell. It isn't a .NET event nor uses EventArgs.
public class EventsManager : ManagedBase {
public delegate void EventDelegate<T>(T e) where T : GameEventBase;
private delegate void EventDelegate(GameEventBase e);
private readonly Dictionary<Type, EventDelegate> delegates = new Dictionary<Type, EventDelegate>();
private readonly Dictionary<Delegate, EventDelegate> delegateLookup = new Dictionary<Delegate, EventDelegate>();
public void AddListener<T>(EventDelegate<T> del) where T : GameEventBase {
// Early-out if we've already registered this delegate
if (delegateLookup.ContainsKey(del)) {
return;
}
// Create a new non-generic delegate which calls our generic one.
// This is the delegate we actually invoke.
EventDelegate internalDelegate = (e) => del((T) e);
delegateLookup[del] = internalDelegate;
EventDelegate tempDel;
if (delegates.TryGetValue(typeof (T), out tempDel)) {
delegates[typeof (T)] = tempDel + internalDelegate;
}
else {
delegates[typeof (T)] = internalDelegate;
}
}
public void Raise(GameEventBase e) {
EventDelegate del;
if (delegates.TryGetValue(e.GetType(), out del)) {
del.Invoke(e);
}
}
}
Your problems seem to be solved if you use the EventAggregator pattern.
There is a short description of it by Martin Fowler
Some very good implementations of it already exist, for example in caliburn micro and
Microsoft Prism
The general idea is that you simplify event registration and deregistration and have a single source of events for many objects.
I never had performance issues with it. You simply put a _eventAggregator.Subscribe(this) when you want to start listening to events for an object and Unsubscribe if you want to stop. Whereever you want to fire an event, just publish it, EventAggregator does the routing.
This once again looks like an XY problem. OP seems to want to have a central place to handle event handlers, registration and disposal. The OP has gone down the route of trying to create a pattern that deal with this in a generic way, but has not looked into the state of the art regarding how this problem is typically solved. He has now come up against a problem in his design and is now asking for a solution to THAT problem, rather than the original problem of event handlers.
There are two good solutions to event handler registration lifecycle management that I know of in .net.
Weak Event Handler
You state that "It would be really bad if someone forgot to remove an event in the RemoveEventsListeners()." Yet do not actually mention WHY it is bad. Typically the only reason for this being bad is that the event handler will now keep an object in reference, that should be collected. With weak reference event handlers, the GC will still be able to collect your object, even when it subscribes to an object that is still alive.
Rx.Net
Rx.Net abstracts event registrations into IDisposables, which you can tie to the object's lifetime, assuming of course you want to control the lifetime of the registrations.
However I actually find the IObservable pattern much nicer to work with than event handler pattern, mostly because C# lacks first class support for event handlers (this is not the case with F#).
F#
Most of your problems will have stemmed from the short sighted design of events keyword handling in C# (specifically not making events a first class construct). F# however does support first class events, and thus should be able to support the pattern you are trying to construct.
Thus with this option you should scrap your code base and rewrite it in F#.
*EDIT added tongue in cheek option of rewriting in F#.

using WPF 4.5 Generic Weak Event Manager for Handled Routed Events?

I would like to know how to convert the subscription of "Handled" RoutedEvents to WeakEventManager?
UIElement has the following method to subscribe to "Handled" RoutedEvents:
UIElement.AddHandler(RoutedEvent routedEvent, Delegate handler, bool handledEventsToo)
So how do I convert it the the Generic WeakEventManager form?
You should be able to just follow the guide for creating a custom event manager from MSDN, and implement StartListening and StopListening like this:
protected override void StartListening(object source) {
var sourceElement = (UIElement)source;
sourceElement.AddHandler(RoutedEvent, OnRoutedEvent, true);
}
protected override void StopListening(object source) {
var sourceElement = (UIElement)source;
sourceElement.RemoveHandler(RoutedEvent, OnRoutedEvent, true);
}
I don't think it would make much sense to use the generic WeakEventManager for this, because it uses an event name and calls Type.GetEvent internally, which isn't useful at all when you're using RoutedEvents and AddHandler instead of "real" events. However, you may be able to write your own generic base class for working with RoutedEvents.
Personally, I use my own weak event solution based on Dustin Campbell's WeakEventHandler. The nice thing about it is that instead of managing adding and removing internally, it gives you a "weak" version of the original delegate which you can pass around freely... so there is no need to customize the weak event manager's implementation when adding delegates in a different way, because the usage is the same in both cases:
uielement.MouseDown += weakMouseDownHandler;
uielement.AddHandler(UIElement.MouseDownEvent, weakMouseDownHandler, true);

Unsign all event listeners, C# code example

I have a C# class which introduce a new custom event type, and allows users add or remove listeners to it. Also I implement a method which revoves all event listeners during dispatch;
public event EventHandler DataCommited;
private void DetatchListeners()
{
if (DataCommited != null)
{
foreach (EventHandler eh in DataCommited.GetInvocationList())
{
DataCommited -= eh;
}
}
}
It is possible to implement a method which will be taking DataCommited event as an argument. So, I can unsign a set of events using one method. I tried a lot ways implementing it, but unfortunately failed to do it. I wonder if it is actually possible and how. Thank you!!!
It is possible to implement a method which will be taking DataCommited event as an argument.
Well, not really. You can take an EventInfo, but that's all. It's important to understand that this statement:
public event EventHandler DataCommited;
actually creates two things:
An event, which code in other classes can subscribe to and unsubscribe from
A field of type EventHandler, which you can use to call the handlers, or get each one individually.
A simpler implementation of your current code would simply be this:
public event EventHandler DataCommited;
private void DetatchListeners()
{
DataCommitted = null;
}
Unsubscribing from a field-like event just changes the value of the field, after all.
However, if you have an EventInfo, you don't know how that event is implement. It may be backed directly by a field - it might not be... there's no general way of asking an event for its current handlers, or setting a new list of handlers. All you can do directly with an event is subscribe and unsubscribe.
If you only use field-like events, you could use reflection to find the name of the field and set the value to null. You can't do it in general though.
See my article on delegates and events for more information.

Events convention - I don't get it

My class with an event:
public class WindowModel
{
public delegate void WindowChangedHandler(object source, WindowTypeEventArgs e);
public event WindowChangedHandler WindowChanged;
public void GotoWindow(WindowType windowType)
{
this.currentWindow = windowType;
this.WindowChanged.Invoke(this, new WindowTypeEventArgs(windowType));
}
}
Derived event class:
public class WindowTypeEventArgs : EventArgs
{
public readonly WindowType windowType;
public WindowTypeEventArgs(WindowType windowType)
{
this.windowType = windowType;
}
}
Some other class that register it to the event:
private void SetupEvents()
{
this.WindowModel.WindowChanged += this.ChangeWindow;
}
private void ChangeWindow(object sender, WindowTypeEventArgs e)
{
//change window
}
What have I gained from following the .Net convention?
It would make more sense to have a contract like this
public delegate void WindowChangedHandler(WindowType windowType);
public event WindowChangedHandler WindowChanged;
Doing it this way, I don't need to create a new class and is easier to understand.
I am not coding a .Net library. This code is only going to be used in this project. I like conventions but am I right when I say that in this example it does not make sense or have i missunderstood something?
Viewed in isolation, yes, you're correct: the .NET conventional syntax is more verbose and less intuitive, but there are advantages:
Future changes to the information passed by your event do not automatically require changes to every consumer of the event. For example, if you wanted to add an additional piece of information to your event--say, a WindowTitle string--you'll have to modify the signature of every single function that gets attached to that event, regardless of whether or not they use it. With the EventArgs approach, you add the property to the arguments and only alter the functions that need to take advantage to the additional information.
Since .NET 2.0 introduced the EventHandler<TEventArgs> delegate type, you no longer need to define your own event delegates manually. In your example, you would type your event as EventHandler<WindowTypeEventArgs> instead of WindowChangedHandler.
The EventArgs approach makes it easy to pass multiple types of information back to the calling function. If you needed to do this in your alternative example (that passes the event parameter directly), you'd still end up creating your own -tuple class to hold the information.
The impact of the first one is made more evident when you look at the actual pattern for .NET events in creating a protected virtual function that actually does the invoking. For example:
public event EventHandler<WindowTypeEventArgs> WindowChanged;
protected virtual void OnWindowChanged(WindowTypeEventArgs e)
{
var evt = WindowChanged;
if(evt != null) evt(this, e);
}
There are a couple of things I'd like to point out here:
Using the pattern of creating this event-invoking method allows you to avoid null checking throughout your code (an event without any functions attached to it will be null and will throw an exception if you try to invoke it)
This pattern also allows classes that inherit from you to control the order of invocation, allowing them to execute their code explicitly either before or after any outside consumers
This is especially important in multithreaded environments. If you just said if(WindowChanged != null) WindowChanged(this, e);, you would actually run the risk of the WindowChanged event becoming null between the time you check it and the time you call it. This isn't important to do in single-threaded scenarios, but is a great defensive habit to form.
I recognise your confusion! I had the same feeling when I first looked at this too.
The big thing to realise is that it doesn't give you much of an advantage programmatically speaking, but it is a convention that is well known in the framework. As such, there are plenty of tools that expect the void EventName(object sender, EventArgs e) signature. Some IoC containers, for example, can use this signature to auto wire events at construction time.
In short, it looks a bit weird, but it's a convention. Stick with it and the bulb will light up eventually!
You can use your delegate. Nobody will force you. It's just a good pattern for events.
If you use standart Sender-EventArgs pattern you'll be able to use the same ChangeWindow handler for other events too.

Subscribe event to event in C#?

Is it possible in C# to connect one event to another so emitting first event will emit second one? The only way i can see is to create a stub function that will emit second event and connect the first event to this function. Compiler do not want to connect event to event or event to anonymouse function / lambda that calls another event:
class Ui { public event EventHandler OnClick; }
class Logic { public event EventHandler OnExit; }
var ui = new Ui();
var logic = new Logic();
ui.OnClick += logic.OnExit; // Not working.
ui.OnClick += ( a, b ) => logic.OnExit; // Not working either :(.
Maybe it's some decorator available or some black magic that allows to chain events without stub functions?
You cannot do this, because you generally cannot do anything to an event from outside the object which owns it except for adding and removing handlers. In particular, you cannot list the existing registered handlers, and you cannot raise it. In your case, "copying" the event is essentially the same thing in disguise, and would allow you to circumvent this restriction; therefore, it's not allowed.
See this recent answer of mine for a more in-depth explanation of why things are the way they are - I just don't feel like retyping it all here.
For your particular case, if you own both classes, the workaround is to make them cooperate specifically - make Ui be aware of the associated Logic instance, and add event handlers to Logic.OnClick in Ui.OnClick.add implementation. Of course, this introduces coupling; you can reduce it to some extent by using more generic interfaces, but you can't get rid of it entirely.
As a side note, OnClick is not a good name for a .NET event. Common naming guide says that it should be simply Click (and OnClick should be the name of a protected virtual method that raises it).
You could do this by hiding the underlying event for Logic and then controlling calls to Add/Remove which require a UI parameter.
public class UI {
public EventHandler OnClick;
}
public class Logic {
private event EventHandler _onExit;
public void AddOnExit(UI ui, EventHandler e) {
ui.OnClick += e;
_onExit += e;
}
public void RemoveOnExit(UI ui, EventHandler e) {
ui.OnClick -= e;
_onExit -= e;
}
}

Categories

Resources