Pass an event into a constructor - c#

I have a class that I want to be able the handle the mouse up event for a grid.
I tried to create it with a static method call like this:
MyDataBinding.BindObjectsToDataGrid(ListOfObjectsToBind, myGrid.MouseUp);
The end goal being that in the method I would assign a delegate to the MouseUp
PassedInMouseUp += myMethodThatWillHandleTheMouseUp;
Looks good here (to me) but the compiler chokes on the first line. It says that I can only use MouseUp with a += or a -=.
Clearly I am going about this the wrong way. How can I get a different class to handle the mouse up with out having to:
Pass in the whole grid
Expose the method that will be handling the mouse up as a public method.
Or, is this just a limitation and I will have to do one of the above?

This is not possible without reflection.
Like properties, .Net events compile to a pair of accessor methods - add_EventName and remove_EventName. There is nothing that you can pass as an argument.

Related

c# event with multiple function overloads

I am trying to make some events the someone can subscribe to, But i want to give the option to use different types of voids that can be used. See the following for clarification:
public event Action<float, float> MouseMove;
public event Action<Vector2> MouseMove;
public event Action MouseMove;
sending of the events
MouseMove(MouseX, MouseY);
MouseMove(new Vector2(MouseX, MouseY));
MouseMove();
So now in threory the user can subscribe in the following ways:
c.MouseMove += DoWithMouseMove;
And now this user has the ability to create the following types of functions depending on his needs like so:
static void DoWithMouseMove(float x, float y)
{
Console.WriteLine(x +" "+ y);
}
or use the following pattern:
static void DoWithMouseMove()
{
Console.WriteLine("Mouse is moving");
}
But this isnt possible because i get the following error:
already contains a definition for 'MouseMove'.
On the class that contains the events
How can i do this or is this not possible?
If something is unclear or needs further clarification let me know, so i can edit the question!
To my knowledge, it is impossible.
Events are little more then a wrapper around a Delegate. They add a public add and remove function, while turning the backing variable Private.
And I do not know of a way to "mix" delegates in the same delegate variable.
Plus even if you could do that, how would you sensibly raise those events? You as the writer of this class are responsible to raise those events and fill all those Parameters. Ideally using a protected RaiseEvent() function.
It is also wierd why you think you need this. In your example, you would propably implement the first option. A event user that does not care for the values (public event Action MouseMove;) would just not retreive those values. And a user that needs a vector (public event Action<Vector2> MouseMove;) could just build one himself from those values.
Edit: I also second that you should follow the established Event pattern: (object sender, customEventArgsInstance e). Do not throw arguments just randomly into the signature, that makes it hard to proces your event.

What's the standard to make an event that doesn't pass any information along?

I've got an event that literally just lets the user know something happened. They have to manually take action for that event, as no data is passed from it.
However, I'm not sure what would be more idiomatic:
public event Action MyEvent;
//clearly says no arguments
public event EventHandler MyEvent;
//uses the EventHandler class to no effect, but might be more idiomatic.
public event Action<object> MyEvent;
//just like the first but passes the sender if needed.
Which would be the standard way to do this?
The idiomatic approach would be to just use EventHandler. Pass in an appropriate sender if you have one or null otherwise, and EventArgs.Empty.
I know it's somewhat crazy, but that's the convention. Bear in mind that plain EventArgs has no useful information in it, so any EventHandler-based event is basically saying "I may get a sender, but that's probably all."
However, with delegate variance as of C# 2, there is a benefit to this: you can use the same event handling method for all events which follow the convention... so you can have (say) logging event handlers which use reflection to dump whatever information they are given in the EventArgs, even if they don't know about it at compile-time.
It's not the greatest argument in the world for a convention, admittedly - but it's a reasonably strong one. Of course routed events are slightly different in how they're subscribed, but even so the delegates follow the same pattern.

Dictionary of events

Is there anything in c# that you can use to create a collection of events like lists, hashsets, and a dictionary in this case? Thankyou.
Sure you can:
Dictionary<String, Delegate> m_events = new Dictionary<String, Delegate>();
In Jeff Richter's Book CLR via C# you can find a complete implementation of an EventSet class.
(Even if you don't have the book you can download the sample code from https://www.wintellect.com/wp-content/uploads/2017/09/CLR-via-C-4th-Edition-Code.zip. The class in question is in "Ch11-1-EventSet.cs".)
As far as the question goes what an event is:
Say you have this line of code in your class:
public event EventHandler<NewMailEventArgs> NewMail;
then the C# compiler will translate the line above into three constructs:
A private delegate field. (Something like: private EventHandler<NewMailEventArgs> NewMail;
A public add_Xxx method (where Xxx is the Event name) that interested subscribers can use to register a callback delegate with the event.
A public remove_Xxx method (where Xxx is the Event name) that subscribers can use to unregister from the event.
(All the gory details can be found in section 11.2 of aforementioned book.)
So in other words the 'thing' you can store in your Event collection class is just a plain old delegate nothing else.
An event is like a property or method; you cant store instances of them. You can use reflection, but this likely isn't what you want.
Did you mean you want to store a list of methods to call when your event is fired? Events already do that.
EDIT:
Ah, I think I get it now. If you just simply fire your event, only the B instances that want it will get it. If you pass into the event args the instance of A that fired the event, then the B instance will be able to tell where it came from. But a B will never get an event from an A that it didn't ask for an event.
EDIT:
Maybe not. You only want to fire an event on one of the B's? Make B implement an interface that has a callback method. Instead of firing an event, call the method on the correct instance of B.
You could use IList with out any trouble. Type T could be any type defined in .net or user defined class.

Why can I check some event handlers for null, some not?

I have a ugly piece of code that adds event handlers. The problem is, if the code is called multiple times, the event handlers are called multiple times.
To solve the problem, I remove the event handler first and then add it.
Now I've seen the following behaviour:
Some event handlers can be checked like:
if (object.event == null) {
//
// Code
//
}
others of the form
if (object.object.event == null) {
//
// Code
//
}
I get a message like 'object.object.event' may only occur left of -= or +=.
(Since I'm using a german version of visual studio, I don't know the correct translation to english).
I have no idea why the behaviour looks this inconsequent so I would be grateful for some information on this.
To be more specific: It's user control.
if (myControl.Event == null) {
//
// works
//
}
if (myControl.TreeView.NodeMouseClick == null) {
//
// doesn't work
//
}
To solve the problem, I remove the event handler first and then add it.
That doesn't solve the problem. The event keyword provides accessors for a delegate object. Much like a property provides accessors for a field. On a property, you always need one get or set. An event has the add, remove and raise accessors. But the compiler will generate a default implementation for them if you don't do so yourself. Which is fairly common.
The advantage of a property accessor is that the backing field can be private. Nobody can mess with it, except the class that contains the field. All access has to go through the get and set accessors. The event keyword works exactly the same way, nobody can mess with the delegate object, except the code in the class that contains the event.
Which shoots a gaping hole in your attempt to avoid raising the event. You cannot mess with the list of subscribers for an event that's declared in another class, the compiler is telling you this. The normal way this is done is setting a bool flag to indicate that events have to be temporarily ignored. The event handler can check that flag and avoid executing any side-effects.
SLaks is correct, and has linked to some excellent resources. Here's a relevant quote from Chris Burrows' blog article:
Let me take a quick detour here and explain to you how the binding of += works in C#. There are two possibilities:
either there is an actual + operator, such as with ints, and x += y binds to “x = x + y” except that x is only evaluated once. This is the compound assignment operator; or
the thing on the left hand side is an event, and x.E += y binds to “x.add_E(y)”. This is the event accessor operator, and in fact this is the only way to bind to an event accessor.
So what do we have in the snippet above? Well, the extra bit of detail that you need to decide is the following rule about field-like events in C#: outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.
In your case, when resolving myControl.Event, you're inside the myControl class, so you don't see an event object; instead you see an actual delegate object, which you can compare with null. When resolving myControl.TreeView.NodeMouseClick, you're outside the TreeView class, so you can't access the actual delegate object; all you get is the event object, which cannot be compared to null.
If I understand correctly, all of this wouldn't help you anyway, since presumably after you check for null, you're going to try to fire the TreeView's event for it, which you can't do.
Depending on what you're trying to do, you could probably subclass TreeView and add an internal method that would call the protected TreeView.OnNodeMouseClick method to fire the event.
You can only access the backing field for an event defined in your class.
For more information, see the spec. (Although this has changed in C# 4, the changes are irrelevant to you)
Best practice in your case would be to create a protected internal OnEventName method in each class.
You can only query your own eventhandlers for attached listeners.
Automatic events, like this one:
public event EventHandler SomethingHappened;
are implemented by the compiler using a multicast delegate.
When you write myControl.Event == null, the compiler actually needs to call Delegate.GetInvocationList on that delegate. The compiler does not let you do that unless the code is inside a method of the class exposing the event, hence the error (it only allows you to add or remove from the invocation list).
If we were talking about an event you define in your own class, then you would have the option of exposing the invocation list (e.g. through a method) and doing what you are trying to do. But for existing classes (e.g. TreeView) it is not possible.

What's the Best Practice for Firing Manual OnClick Events?

I've got an XNA project that will be drawing several objects on the screen. I would like the user to be able to interact with those items. So I'm trying to build a method that checks to see which object the mouse is over, out of those which is the top most, and then fire an OnClick event for that object.
Checking for the things above is not the problem, but where to actually put that logic is most of the issue.
My initial feeling is that the checking should be handled by a master object - since it doesn't make sense for an object, who ideally knows only about itself, to determine information about the other objects. However, calling OnClick events remotely from the master object seems to be counter-intuitive as well.
What's the best practice in this situation?
Thanks,
Tyler
Don't put the logic in the event handler. Instead have the event handler call another method, passing the clicked object as argument:
// inside the OnClick event handler
ActOnObject(clickedObject);
Then you can call the same method anywhere else in the code, for any object:
ActOnObject(GetObjectUnderMouse()):
I would probably have something like an "ObjectManager", a class that would hold a collection of the objects and would handle the finding of the current object that should be clicked upon, and then call the click function on that object. Since the object itself isnt handling the click (it could but in my example technically the overall game itself, or possibly the ObjectManager is the one that catches the click) then i would just take the object that you want to click on and call something like
Object.Click(whatever parameters are logical for your situation)
in the end I think I am suggesting a very similar approach as Fredrik, however the main difference is I personally prefer the "Object" to know what should be done with the click, and thus call the function on the object itself - which might be what you would do in the function suggested above as well...
Well , for graphical objects (textures , sprites or the kind ..)
public MyObject()
{
....
public AreTheseMyCoordinates(int X, int Y);
}
Where , you get the screen coordinates of the mouse position.
Or you can make a Helper Class:
public static MouseHelper
{
public static IsObjectClicked(MyObject obj, int X , int Y)
{
....
}
}
I`d go with the static helper.

Categories