by
kirupa | 25 April 2009
In the
previous page, I explained how to
programmatically assign events to event handlers.
This page will wrap things up by explaining one
advanced case involving events that you may run
into.
When
you are dynamically creating elements and having
event handlers listen to events on them, knowing
which element fired the event will be important. For
example, let's say I programmatically generate a
grid of buttons as shown below:
The code for
generating them is similar to what you saw before,
but the difference is that I place it all inside a
for loop so that I
can get nine copies of the element instead of just
one:
- public
MainPage()
- {
- // Required to
initialize variables
-
InitializeComponent();
-
- for
(int
i
=
0;
i
<
9;
i++)
- {
- Button
squareButton
=
new
Button();
- squareButton.Height
=
100;
- squareButton.Width
=
100;
- squareButton.Margin
=
new
Thickness(10,
10,
10,
10);
- squareButton.Style
=
this.Resources["MyCustomButtonStyle"]
as
Style;
-
- squareButton.Content
=
i;
- squareButton.Click
+=
new
RoutedEventHandler(ButtonClick);
-
- SquareHolder.Children.Add(squareButton);
- }
- }
-
- private
void
ButtonClick(object
sender,
RoutedEventArgs
e)
- {
- Button
clickedButton
=
sender
as
Button;
-
- if
(clickedButton
!=
null)
- {
- MessageBox.Show(clickedButton.Content.ToString());
- }
- }
Notice that each
button you create has the Click event wired up to
the ButtonClick event handler. If you had to
visualize how this would look, it would look as
follows:
Even though you have
nine buttons, you only have one event handler that
gets called each time the button gets clicked. The
problem is, how will you know which button initiated
the click event that caused the event handler to get
called?
The way you do that is by using your event
handler's arguments. The first argument is an object
whose name is sender:
- private
void
ButtonClick(object
sender,
RoutedEventArgs
e)
- {
- Button
clickedButton
=
sender
as
Button;
- MessageBox.Show(clickedButton.Content.ToString());
- }
Each time your event handler gets called, this
sender object contains a reference to whatever
element fired the event. The thing to note, though,
is that sender is of type
object. This is as generic as something can
get in .NET.
What you need to do is actually cast your sender
as something a bit more specialized. If you know
what control all of the clicked items will be, you
can just cast your sender as that control itself. In
our example, because this event handler is only
being called by Button, I can safely cast the sender
as a Button:
- private
void
ButtonClick(object
sender, RoutedEventArgs
e)
- {
- Button
clickedButton
=
sender
as
Button;
- MessageBox.Show(clickedButton.Content.ToString());
- }
You may be wondering why you need to worry about
casting your sender object as the type that you
want. The reason is that, objects in .NET can take
various forms. The form they take dictates what they
are capable of, and more importantly, what they
allow you to access.
Having your Button actually be cast as a generic
object, you only have access to the following
properties:
By casting my sender as a Button, I have access
to all properties any Button object would have:
The sender that gets passed in did not change.
What properties the sender actually exposed did
change depending on whether it was cast as an object
or as a Button. You should be careful though. If you
cast your sender into something it isn't, especially
if it is something more specialized, then you will
run into various errors and exceptions.
One of the takeaways of this
article is that everything you can do in Expression
Blend, you can do in code itself. The downside is
pretty obvious. You get no friendly design-time
support. Everything you do only becomes visible when
you run your application in your window or browser,
and that can make designing complicated UIs very
cumbersome.
Instead, what you
should look at is see what makes the most sense for
you. In general, most applications you create will
rarely require you to create visual elements via
code for insertion into a visual tree. In all my
years of fiddling with this in Flash and
Silverlight/WPF, I primarily use this technique for
procedural animations where dynamically adding and
moving things around the screen is really cool.
Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!
|