Event Args

M

MySelf

Hello,

I am working on an application in C#, and I am programming a function
to process the result of an event OnSelectionChanged from a
DataGridView.

My concern is that I don't know the type of arguments I should use in
this function for a cast to recover the information provided by the
System.EventArgs value transmitted by the system in the following way :

void gridView_SelectionChanged(object sender, System.EventArgs e)
{
WhichType mydata = e as WhichType;
}

And generally, how can I know which type of data is sent to me by
Windows in such a situation ?

Thank you.
 
J

Jeff Johnson

I am working on an application in C#, and I am programming a function to
process the result of an event OnSelectionChanged from a DataGridView.

My concern is that I don't know the type of arguments I should use in this
function for a cast to recover the information provided by the
System.EventArgs value transmitted by the system in the following way :

void gridView_SelectionChanged(object sender, System.EventArgs e)
{
WhichType mydata = e as WhichType;
}

And generally, how can I know which type of data is sent to me by Windows
in such a situation ?

You never, ever, EVER need to cast the event args to another type unless you
are dealing with some horribly-written third-party code. The argument
containing an EventArgs type (or one derived from it) will always be a
concrete type. Anything else is a huge breach of convention.
 
M

MySelf

Dans son message précédent, Jeff Johnson a écrit :
You never, ever, EVER need to cast the event args to another type unless you
are dealing with some horribly-written third-party code. The argument
containing an EventArgs type (or one derived from it) will always be a
concrete type. Anything else is a huge breach of convention.

EventArgs is a genric type, isn't it ? To use the data on it, I must
cast it to a more specific type, or not ?
 
M

MySelf

Peter Duniho a exposé le 05/04/2011 :
System.EventArgs most definitely is _not_ a "generic type". In C#, a
"generic type" is a very specific thing, and System.EventArgs is not it.

Well, in my code, when I hit e and a dot, wainting for autocompletion,
I only get "Equals", "GetHashCode", "GetType" and "ToString" methods.

How can I get more information from this e value, if not by casting it
?

And if I don't cast it, what is this e value made for ?
 
J

Jeff Johnson

MySelf said:
Dans son message précédent, Jeff Johnson a écrit :

EventArgs is a genric type, isn't it ? To use the data on it, I must cast
it to a more specific type, or not ?

Don't use the word "generic" to describe what you're trying to describe.
You're talking about EventArgs being a BASE class for all other classes that
pass arguments to event handlers. While it's okay in conversational English
to use "generic" this way, it is not good to use it this way in the context
of C#, because "generic" has a very specific meaning there.

Let's take a step back and talk about the .NET paradigm for event handlers.
First and foremost, .NET 1.0 introduced a new convention for the signature
of event handling methods, and all subsequent versions have followed this
convention religiously, and Microsoft has urged developers to do so as well.

In the days of VB, event handlers could have a variable number of
parameters, depending on what kind of data the event source wanted to pass
on to its subscribers. .NET said "This needs to change." The new direction
was to always pass exactly two parameters to any event handler. The first
parameter is always of type object and refers to the class instance that
raised the event. By convention it is named "sender." The second parameter
is always of type System.EventArgs or a class ultimately derived from
System.EventArgs, and by convention it is called e.

If any data needs to be passed to the event handler, it is passed in
properties of an EventArgs-derived class. That way event handler signatures
are always uniform, and look like (again, by convention)

<access method> void <object name>_<event name>(object sender,
<EventArgs-descended type> e)

Some events never need to pass any information. An example of this is the
Changed event of a text box. The text box doesn't tell you WHAT has changed,
merely that a change has occurred. If you need to know what changed, you
have to check the current value of the Text property against the previous
value (which you need to have saved earlier). Because no additional data
needs to be sent during a Changed event, the event delegate uses the base
System.EventArgs class as the type of e. System.EventArgs has no members
beyond what it inherits from Object. (Well, except for the static Empty
field; the point is it has no properties with which to pass data.)

If you need to pass additional information to an event then you need to
either use a Framework-provided EventArgs descendant or you need to roll
your own. But when you do this you really should change the declaration of
your event to use the new class. Let's just go to an example. I'm going to
create an event that needs a Progress property. Your code might look like
this:

public class ProgressEventArgs : EventArgs
{
// I'm leaving off any validation.
// Yes, at the moment you could set negative progress.
// Perhaps this class will be used for politicians....
public int Progress { get; set; }

public Progress() { }

public Progress(int progress)
{
Progress = progress;
}
}

Now for the class that will expose an event:

public class Something
{
// This syntax for declaring events was new as of Framework 2.0.
// I prefer it to the original delegate syntax and therefore I'm
// using it in my example.
event EventHandler<ProgressEventArgs> ProgressChanged;

// Code to raise the event is outside the scope of this discussion,
// so I omit it
}

The event is declared to use the type ProgressEventArgs. This will affect
the signature of the event handler method.

In the subscribing class you would write a handler that looks like this:

private void something1_ProgressChanged(object sender, ProgressEventArgs e)
{
if (e.Progress < 100)
{
// ...
}
}

Notice how the event handler uses the exact same class that was specified in
the declaration of the event. This is how your code should be written. What
you seem to think is the case, however, is that the event is declared like
this:

event EventHandler<EventArgs> ProgressChanged;

and that the event handler should look like this:

private void something1_ProgressChanged(object sender, EventArgs e)
{
ProgressEventArgs actualType = e as ProgressEventArgs;
if (actualType.Progress < 100)
{
// ...
}
}

That is completely wrong. If you ever have to write code like this then I
say something has been designed badly. I have never once seen code that
required me to cast the incoming e parameter, and despite what Pete
suggested, I think that in this particular case, the convention of an event
handler using a concrete class has been adopted 99.999999999% of the time.
 
M

MySelf

Jeff Johnson vient de nous annoncer :
Don't use the word "generic" to describe what you're trying to describe.
You're talking about EventArgs being a BASE class for all other classes that
pass arguments to event handlers. While it's okay in conversational English
to use "generic" this way, it is not good to use it this way in the context
of C#, because "generic" has a very specific meaning there.

Thank you for taking the time to write this explanation. It is exactly
what I needed and wanted to get a good understanding of these notions !
 
J

Jeff Johnson

Your example suggests that you misunderstand me.

Broadly, this is the scenario (note more compliant EventArgs subclass
naming :p ):

event EventHandler<ProgressChangedEventArgs> ProgressChanged;

Whoa, nelly! Big disagreement on this part. Nowhere, in neither
documentation nor actual usage, does the .NET Framework suggest that an
event args derivative should be named based on the event it will be used in.
Think of all the mouse events. Are there MouseDownEventArgs,
MouseUpEventArgs, and MouseMoveEventArgs classes? No, there is simply
MouseEventArgs. The event args derivative should be named for its function,
not for the event which will use it. (An even better example is
CancelEventArgs.) My class serves to provide information about progress,
whether that be initialization, change, or termination (okay, I'm stretching
this a bit since there's not a whole lot that progress does other than
change, but I think you catch my drift), and therefore the--pardon the
term--"generic" ProgressEventArgs is the better way to go.

As for the rest of your post, I truly understand where you're going with it
but I cannot agree in this one case (i.e., writing event handlers). I think
part of it is because, really, who actually MANUALLY writes their own event
handler skeletons? I have to assume the overwhelming majority of us either
double-click on the item in the Properties window or we use Intellisense to
auto-complete the wire-up in code, at which point Visual Studio will supply
the concrete class in the definition. It's a scenario I chalk up to "an
exception to the rule," with the rule being "if it makes more sense to the
programmer to do it that way, they should." But that's just me.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top