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.
You look at the event declaration. The signature of the delegate type
used to declare the event is exactly the type for the second argument
that will be sent to you.
In the case of the "…Changed" events, in .NET these are always (or at
least, for every example I know of) events using the EventHandler type,
and the EventArgs object that is passed to your handler is always just
of type EventArgs (and in fact, should always be the EventArgs.Empty
instance…though your program shouldn't rely on that). Since the event
is raised simply to tell you about a specific member that's changed,
there is no other data to pass to the handler and thus no need for
anything other than EventArgs itself.
If some other sub-class of EventArgs is being used, then that type will
be part of the delegate type signature for the event.
Pete
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 ?
I disagree. As with all broad generalizations, there will always be
valid exceptions.
Delegate types are covariant. It is possible to write a single event
handler that accepts EventArgs as the argument type, but which is used
for more-specific EventHandler delegate types. In those cases, one
_would_ need to cast the EventArgs value to the more-specific type
associated with the more-specific EventHandler delegate type.
Granted, this scenario should be very rare. But it's not unheard of,
and doesn't even necessarily imply a broken design.
Pete
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 ?
That has nothing to do with "generic". That just means that the type
hasn't declared any additional instance members and just has what it
inherited from System.Object.
See http://msdn.microsoft.com/en-us/library/512aeb7t.aspx
> How can I get more information from this e value, if not by casting it ?
You can't. As I already explained, the type being passed to you is just
System.EventArgs. There is no "more information" to be gotten. It
doesn't exist.
> And if I don't cast it, what is this e value made for ?
It is there so that every event declared in .NET follows a specific
pattern for the delegate type signature, even the simplest ones. One
particular benefit is that it allows for a single event handler method
to be able to handle more than one kinds of event.
As I wrote in my reply to Jeff, this doesn't and really shouldn't come
up very often. But it's a useful feature in those moments when it does.
There is also the pedagogical benefit of simply making every event
delegate type look the same. Whether this was a motivating factor for
the people who designed the .NET API, I don't know. But it could have been.
Pete
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.
Your example suggests that you misunderstand me.
Broadly, this is the scenario (note more compliant EventArgs subclass
naming :p ):
event EventHandler<ProgressChangedEventArgs> ProgressChanged;
Then the method you posted, with this declaration:
private void something1_ProgressChanged(object sender, EventArgs e)
{
// …
}
can be used with the ProgressChanged event:
Something something1 = new Something();
something1.ProgressChanged += something1_ProgressChanged;
Why would someone want to do that? Consider the scenario where the
event subscriber doesn't really need to know the information in the
EventArgs object. They just want to know that the event happened.
In fact, the ProgressChanged event is a decent example of such a case;
most of the time, we look at the Percentage value in order to display
some progress indicator, but it's not required to do so. There may be
scenarios where the event is used more as a "heartbeat", or the specific
progress information will be retrieved elsewhere (perhaps the subscriber
wants to report some information that's not in the
ProgressChangedEventArgs class).
Now suppose you have two or more similar events like that, where you
want to handle them all the same way, but don't need the data in any of
them, or perhaps they are substantially the same, but for one you do
want to look at something specific. In that case, you would again have
the void Method(object, EventArgs) signature, reusing the method for
each of the events. And if you want to look at something specific for
one of those events, you can cast the EventArgs object as necessary.
One might argue that there are other ways to accomplish the same. And
that's true. But fact is, assuming the above scenarios, I really don't
see a huge problem implementing them in the way I describe. It won't
come up much, won't cause any serious problems, and if it makes more
sense to the programmer to do it that way, they should.
Pete
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 !
>> 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.
>
> 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.
Sounds like you're making a mountain of a molehill.
> 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.
http://msdn.microsoft.com/en-us/library/system.componentmodel.progresschangedeventargs.aspx
is one relevant example.
> Think of all the mouse events. Are there MouseDownEventArgs,
> MouseUpEventArgs, and MouseMoveEventArgs classes? No, there is simply
> MouseEventArgs.
That's only because they reuse the same type for more than one event.
Every single example of a one-for-one correspondence uses the
"EventNameEventArgs" pattern. I'd call that a pretty strong recommendation.
> The event args derivative should be named for its function,
> not for the event which will use it. (An even better example is
> CancelEventArgs.)
Again, that's a type that's reused across multiple events.
For such types, it's simply not possible to name them according to the
event for which they are used. These are the very exceptions that
_prove_ the rule.
> 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.
Only if you reuse that type for multiple event names. Absent any
demonstration of that aspect, the basic rule applies.
Now, if you'd like to amend your original post to specify that you do in
fact have a valid exception to the rule, because you reuse that type for
multiple events, I have no problem with that. But to claim that there's
no such rule? Folly.
> 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 use events broadly, not just in the context of the Designer. In fact,
most of the time I'm writing my own event handlers.
Even when using the Designer, I prefer to start with the basic event
handler for a single control, and then reuse that same method for other
controls' events, rather than littering my code with basically identical
event handlers.
> 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,
Actually, Intellisense does an awful job of helping with event
subscriptions. Ever try it? Once you get to the right-hand-side of the
+=, Intellisense just gives up if there's no method present already. It
won't provide a stub, unless you use the old-style explicit constructor
syntax (which not only is ugly, is so much typing you might as well just
have done everything by hand).
> 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.
Go re-read my original reply. I never suggested this would be standard
practice. It was simply a response to your blanket assertion that "You
never, ever, EVER need to cast the event args to another type unless you
are dealing with some horribly-written third-party code."
You should know better than to make such a strongly worded and broadly
targeted claim. Such claims are practically never true; the real world
is far too variable and messy for that to happen.
Pete