EventArgs buttonclick

  • Thread starter Thread starter Michael Soza
  • Start date Start date
M

Michael Soza

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!!!!
 
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
 
hi Pete, thanks for the reply, I'm trying to do what you say but I have
errors that don't understand fully.
When im trying to assign the event handler trough the anonymous method the
intellisense tell me that Options, Actualstatus and treViewDocXml doesn't
exist in the current context, and that is correct, this objects are know in
other form so in this form what is launched trough the main form they are
unknown. What I think is I need to do is: declaring this three members and
initialize trough a overloaded constructor to get the references of the real
objects but is this the correct approach??

In summary:
MainForm has Options, ActualStatus, treviewDocXML objects.
LoadPreviousSXFilesForm is other form launched from the Mainform and has
buttons that need to act over the mentioned object of the MainForm

The code in the Dependent Form is:

public LoadPreviousSXFilesForm()
{
InitializeComponent();
CreateNewSessionAndSXFileDefault.Click +=(sender, e)=>
CreateNewSessionAndSXFileDefault_Click(sender,e,Options,Actualstatus,treeViewDocXml);
}

private void CreateNewSessionAndSXFileDefault_Click(object sender,
EventArgs e, LiteDocOptions Options, Status ActualStatus,
DragDropTreeview treeViewDocXml)
{
Generador.GeneraXml(Options);
ActualStatus = new Status(Options.PreDocFile);
try
{
ActualStatus.ActualNavigator.MoveToRoot();
ActualStatus.ActualNavigator.MoveToFirstChild();
treeViewDocXml.BeginUpdate();
treeViewDocXml.PopulaTreeViewDocXml(ActualStatus.ActualNavigator,
treeViewDocXml.Nodes, false);
treeViewDocXml.EndUpdate();

}
catch (System.Exception)
{
MessageBox.Show("Test");
throw;
}

}
 
Michael said:
hi Pete, thanks for the reply, I'm trying to do what you say but I have
errors that don't understand fully.
When im trying to assign the event handler trough the anonymous method
the intellisense tell me that Options, Actualstatus and treViewDocXml
doesn't exist in the current context, and that is correct, this objects
are know in other form so in this form what is launched trough the main
form they are unknown. What I think is I need to do is: declaring this
three members and initialize trough a overloaded constructor to get the
references of the real objects but is this the correct approach??

In summary:
MainForm has Options, ActualStatus, treviewDocXML objects.
LoadPreviousSXFilesForm is other form launched from the Mainform and has
buttons that need to act over the mentioned object of the MainForm

You should try to avoid that situation altogether. Specifically, if
those are variables in the MainForm class, then your "dependent form"
class should not have access to them.

Depending on the nature of the data, one possible alternative would be
to expose the information as properties on the MainForm class, taking
care to expose only that data that is safe to expose (e.g. for value
types, you can return the value directly, for reference types it may or
may not be necessary to further abstract the reference type being
returned, to prevent the client code (e.g. "dependent form") from
modifying data important to the "MainForm" class.

Another alternative would be to abstract the relevant event(s) further
in the MainForm class, creating a new public event in MainForm that your
"dependent form" can use, but which wraps/hides/abstracts the variables
you're having trouble with.

Without a concise-but-complete code example that reliably demonstrates
the data, your usage of it, and the relationship between the classes, it
would be hard to offer anything more specific.

Pete
 
Back
Top