Adding UI Elements Programmatically - Page 4
       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.

Knowing Which Element fired the Event
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.

Conclusion
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!

Kirupa's signature!

1 | 2 | 3 | 4





SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.