Michael said:
hi all, I wanna know how can I pass information to some eventhandler.
Example a tipical
button1_Click(object sender, EventArgs e) in a Windows Forms Application.
I read in some webs that I need to create a class derived from
System.EventArgs and pass it as argument. This class in theory is gonna
have the information that I need.
My doubt is were is the call of that eventhandler?.........where I can
pass that derived class? I look in ...Designer.cs and in normal cs but a
I can't find were pass the specific object.
Im surely understending something wrong....help!!!!
The advice to create your own System.EventArgs subclass is only useful
if it's your own code raising the event, and thus you have the ability
to dictate what's passed.
I presume that you're instead asking about the scenario where you own
the client code where the event handler is implemented, but you're
dependent on the object owning the event to actually raise the event,
without any control on your part for how it's raised.
In that case, you cannot modify what is passed from the event itself.
But, there are ways you can work around that. It just depends on what
information it is you're trying to pass and how you're using that
information.
The two main strategies are to wrap your event handler to which you want
to pass extra data with an event handler that adds the necessary
information; or to simply have your own event handler do some
manipulation of the information that _is_ passed to resolve the extra
information needed (for example, using the value of the "sender"
argument somehow).
My preferred approach is the first method. This in turn can be done in
a variety of ways too, but my preferred way is to just use a simple
lambda expression.
For example, suppose you wanted to pass an index value of some sort to
the event handler of a Button's Click event. Well, the Click event
itself doesn't allow for that. But, you can get around that anyway.
Just define your event handler with the extra argument you want:
void button_Click(object sender, EventArgs e, int i)
{
// do whatever, including use "i"
}
But rather than hooking the event handler up in the Designer (which you
won't be able to, because of the extra argument), do it explicitly in
the constructor:
public Form1()
{
InitializeComponent();
button1.Click += (sender, e) => button_Click(sender, e, 1);
button2.Click += (sender, e) => button_Click(sender, e, 2);
button3.Click += (sender, e) => button_Click(sender, e, 3);
}
Here, I've shown code where there are three different buttons. For the
Click event of each, I subscribe an anonymous method, declared using the
lambda syntax, that explicitly calls your actual event handler with the
extra argument included.
You can extend this idea arbitrarily; the above is just a very simple
example to get the point across. Do keep in mind though, the example is
using an anonymous method, which means you need to be careful about
using variables, and if you do, understanding the capture rules properly.
For example, here's an alternative implementation of the above:
public Form1()
{
InitializeComponent();
for (int i = 1; i <= 3; i++)
{
Button button = this.Controls.Find("button" + i.ToString(),
false);
button.Click += (sender, e) => button_Click(sender, e, i);
}
}
Sure seems like that'd work great. But, it doesn't. You have to
remember that the content of the anonymous method is real code, executed
when the method itself is executed. And each anonymous method
"captures" the same variable "i" used in every other anonymous method.
By the time any of the anonymous methods used as the actual event
handler for a Click event gets called, the variable "i" will have been
incremented to the value "4", and that's the value _all_ of the calls to
"button_Click()" will use.
Instead, to work correctly, the code would have to look like this:
public Form1()
{
InitializeComponent();
for (int i = 1; i <= 3; i++)
{
int iArg = i;
Button button = this.Controls.Find("button" + i.ToString(),
false);
button.Click += (sender, e) => button_Click(sender, e, iArg);
}
}
Each time through the loop, a new "iArg" variable is "created". That
means that each new anonymous method gets a different variable "iArg"
that is captured by the anonymous method. And of course, that variable
only ever has the one value assigned to it at the beginning of the loop
block.
Code like this can be very flexible, but it does come with certain
potential pitfalls (such as the one I describe above). Also, there is a
certain amount of overhead not just to the anonymous method, but also if
you wind up capturing variables (the compiler winds up having to
generate a hidden class to contain any captured variables, and of course
for each anonymous method instance, there has to be an instance of that
class). So, use it sparingly, where there's some real maintenance
advantage that justifies the potential overhead.
Pete