Controls
Silverlight 2 Beta 2 has over 3 dozen User Interface (UI) controls and the final release will have more. .NET programmers already familiar with ASP.Net or (especially) WPF, will find using the Silverlight controls very natural and straight forward.

Figure 1-1. Silverlight Controls (split in two to make it easier to view)
Silverlight controls were created to look great and provide extensive and customizable functionality right out of the box. Moreover, all of the standard controls can be modified in numerous ways to meet your needs.
The look and feel of the control can be tweaked through styles or can be entirely redesigned through templates, and the behavior of the controls can be modified through event handlers. In the rare cases when none of that is enough, you can create (or derive) your own customized controls as well.
This tutorial will cover event handlers; and Syles and Templates will be covered in tutorials to follow shortly and a tutorial on custom controls will follow.
A Note On The Design Surface
At the time of this writing, the design surface is "read only." That is, you can drag and drop controls into the markup (or write the Xaml by hand) and the effects are seen immediately in the design surface, but you cannot yet drag or otherwise manipulate controls directly in design mode.
That is a temporary limitation. For now, one alternative is to use Expression Blend, and we have a full tutorial on Blend for Programmers that shows how to work with the two environments together.
Note that controls can also be created dynamically (in code, at run time) as explained at the end of this tutorial.
Layout Controls
The use of layout controls is both straight-forward and essential to the creation of Silverlight applications. Layout controls are used to manage the placement of other controls (including other layout controls!) in your Silverlight application. You can think of the layout controls as "containers."
The three Layout controls you'll use most often are:
- Grid - essentially a table used for positioning objects in rows and columns.
- StackPanel - used to position objects next to one another, or atop one another.
- Canvas - used for absolute positioning (and unchanged from Silverlight 1.0)
They are listed in the order of how frequently they are used. And to be honest, if you learn Grid and StackPanel, you can probably program for a long time on just those two.
Grids
Grids (not to be confused with DataGrids) offer easy and exact placement by providing a table-like structure. You declare rows and columns, and then place controls into a specific row/column location (spanning across rows or columns as needed).
While you can tweak your grids to achieve very precise placement, the basic use of grids is extremely straight forward.
You typically declare a grid, declare its rows and columns and then start placing controls into specific cells (e.g., column 1, row 3). To see this at work, let's create our first Silverlight Application: Easy Grid.
Creating The First Example - A Grid With Controls
Open Visual Studio 2008 and click on Create Project and then in the new project window you'll want to create a C# project using the Silverlight Application Template.
Pick a location for your application and give it a meaningful name; be sure that you are building against the latest framework.

Figure 1-2. Creating A New Silverlight Project (Click to view full-size image)
When you click OK you will next be asked if you'd like to generate a Web Site or a Web Application (using the top radio button) or just a test page (using the bottom radio button) or if you'd like to link to an existing web site; all as shown in the next figure.

Figure 1-3. Choose Simple HTML Test Page
If you create just a test page, the project is kept very simple, but if you generate a Web Site or Web Application Project, then Visual Studio creates two projects in your new solution; the Silverlight Application and a test application; excellent for test-based programming but more than we need right now.
Choose the second radio button (HTML Test Page) and let Visual Studio create a simple application for you. If Page.xaml doesn't open automatically, double click on it in the Solution Explorer. You should find that Visual Studio has guessed that you want a grid as your main container, and has created one for you and named it LayoutRoot. (Also note that the very first declaration in each "page" is a UserControl.
<UserControl x:Class="EasyGrid.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
In fact a Page is a UserControl, and we'll return to that relationship in a later tutorial.
The Grid definition created by Visual Studio 2008 looks like this:
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
Many times, your entire application will go between the opening and closing Grid tags; other times you’ll replace the Grid with another container.
Defining Rows And Properties
You define the Rows for a table inside the Grid.RowDefinitions element. For each Row, you add a RowDefinition element, which itself may have various properties, including a specific height, or if you prefer you may set the height to be proportional to the available space or to take all the space not taken by other rows.
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="30*" MaxHeight="70" />
<RowDefinition Height="40*" MaxHeight="70" />
<RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
<RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
</Grid.RowDefinitions>
</Grid>
Height="Auto"
With Auto, the Grid’s space is distributed evenly based on the size of the content within the row.
Star or Proportional Sizing
In proportional sizing the value of a column or row is expressed in Xaml as *.
<RowDefinition Height="*"
However, you can give twice the space to one column or row as another by using 2* (or a 5:7 ration by using 5* and 7*).
<RowDefinition Height="30*"
<RowDefinition Height="40*"
If you combine this with a Minimum or Maximum Height you get finer control over the limits of the row's range of sizes,
<RowDefinition Height="30*" MaxHeight="70" />
<RowDefinition Height="40*" MaxHeight="70" />
<RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
Minimal or Controlled space
By default child elements of grid take up the least amount of space necessary to to accommodate the largest content within a cell in a given row or column. You can take greater control over positioning, however, by using the margin and alignment properties as described below
Sizing Units
To provide the most flexibility, Grid columns and rows are sized by GridLength objects which use the GridUnitType, which in turn allows you to choose among:
- Auto (size based on the size properties of the object being placed in the grid)
- Pixel (size in pixels)
- Star (size based on a weighted proportion of the available space)
designating, if we choose, the minimum and maximum dimensions of each.
To see the effect of all this we'll create five rows using different sizing rules. We'll also create three columns with no sizing rules at all (!). We'll then fill our grid with controls and take a look at some of the effects. Here is the code, which we'll take apart piece by piece.
Example 1-1 . The Xaml for EasyGrid
<UserControl x:Class="EasyGrid.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="30*" MaxHeight="70" />
<RowDefinition Height="40*" MaxHeight="70" />
<RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
<RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock x:Name="FirstNamePrompt "
Grid.Row="0" Grid.Column="0" Text="First Name:" Margin="5"/>
<TextBox x:Name="FirstName"
Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Width="150" Background="Bisque" Margin="5" />
<TextBlock x:Name="LastNamePrompt "
Grid.Row="1" Grid.Column="0" Text="First Name:"
Margin="5"/>
<TextBox x:Name="LastName"
Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
Width="150" Background="Beige"
Margin="5" />
<TextBlock x:Name="SubscriberPrompt"
Grid.Row="2" Grid.Column="0"
Text="Subscriber?" VerticalAlignment="Bottom" />
<CheckBox x:Name="PlanA" Grid.Row="2" Grid.Column="1"
Content="Plan A" IsChecked="true"
VerticalAlignment="Bottom" />
<CheckBox x:Name="PlanB" Grid.Row="2" Grid.Column="2"
Content="Plan B" VerticalAlignment="Bottom" />
<TextBlock x:Name="Hello" Text="Hello"
Grid.Row="3" Grid.Column="2" VerticalAlignment="Bottom"/>
<TextBlock x:Name="World" Text="World"
Grid.Row="4" Grid.Column="2" VerticalAlignment="Bottom"
FontFamily="Comic Sans MS" FontSize="24"
FontWeight="Bold" Margin="0,20,0,0"/>
</Grid>
</UserControl>
The result of the Xaml code is shown in

Figure 1-4. The Xaml as Design
First, it is imperative to understand that the Xaml shown in Example 1-1 is all that is needed to produce the Silverlight control shown in Figure 1-4. It is true that you can't see the rows and columns, but that is easily remedied. Find the declaration of the Grid and set its ShowGridLines property to True (Intellisense will help as shown inFigure 1-5

Figure 1-5. Adding Property ShowGridLines and setting it True (Click to view full-size image)
When you do, the grid lines become visible; which can be very useful during design, as long as you remember to set the property to false before you post your Silverlight application!

Figure 1-6. ShowGridLines Makes The Alignment Very Visible (Click to view full-size image)
Unpacking the Xaml
The first lines create the Grid and define how the rows will share the space.
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True" >
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="30*" MaxHeight="70" />
<RowDefinition Height="40*" MaxHeight="70" />
<RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
<RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
</Grid.RowDefinitions>
As described above, the RowDefinitions define five rows. The first has a fixed height of 50. The second and third will float, but in a 3:4 proportion with one another, but each with a maximum height of 70. The next row will take all the remaining space, but will never be allowed to shrink to less than 30 nor grow to more than 50. The final row will size itself to the object placed in the row, but yet is constrained to no less than 5 and no more than 30.
After the column definitions we define a TextBlock and a TextBox. We'll discuss these controls in more depth later, but the former is typically used as a label and the latter is used to allow the user to put in text.
<TextBlock
x:Name="FirstNamePrompt "
Grid.Row="0"
Grid.Column="0"
Text="First Name:"
Margin="5"/>
The TextBlock has five parameters. They can be aligned one below the other, or strung out all in a line, any way you like. The first parameter is the name (FirstNamePrompt) and is used to allow you to address the object in code. If you give an object in Xaml a name, and save the file, that object is available with no further declaration in your methods
Thus, if you save this file, you will be free to write
FirstNamePrompt.Text=”Hello”
From any method of this class, and the compiler will know exactly what you mean!
The Grid.Row and Grid.Column properties are called extended properties and are really "borrowed" from the immediately surrounding grid to position the TextBlock inside the appropriate cell.
The Text property does just what you expect, it fills the TextBlock with that text.
Margin is a fascinating property, and we'll return to it a couple times. For now, I'll mention that it takes three forms:
- A single value, which gives a margin of that value "all around" - that is left, right, top and bottom
- Two values in which case the first is divided evenly among the left and right margin and the second is divided evenly among the top and bottom
- Four values, in the order Left, Top, Right, Bottom.
The TextBlock label in the first column is followed by an (input) TextBox in the second column. The properties are very similar except that you must declare the width of your TextBox and we choose here to give the TextBox a background color.
The next pair are much like the first.
The third row is filled by a TextBlock and two CheckBox controls. Note that they are aligned by setting their VerticalAlignment properties and that the first CheckBox has its IsChecked property set to True so it will be checked when the page is first shown.
The fourth row has a TextBlock that displays Hello and the final row has a TextBlock that displays World, but does so setting the FontFamily, FontSize and FontWeight.
StackPanels
StackPanels are typically combined with other layout controls. They allow you to stack objects one on top of the other, or next to each other (like books on a shelf).
One convenience of a StackPanel is that you do not have to provide the position of the objects held by a StackPanel, they are positioned relative to the object declared earlier in the Stack..
In the following example, you will stack a TextBlock on top of a TextBox which in turn will sit on top of a Button that will sit on top of a CheckBox (shades of Yertle the Turtle!)
<StackPanel Background="Beige" Orientation="Vertical" >
<TextBlock Text="Your name?"
HorizontalAlignment="Left" Margin="10,2,0,1"/>
<TextBox Width="150" Height="30"
HorizontalAlignment="Left" Margin="10,2,0,1"/>
<Button Content="Submit this information"
HorizontalAlignment="Left"
Margin="10,2,0,1" Height="30" Width="150" />
<CheckBox Content="With Zing!" HorizontalAlignment="Left"
Margin="10,2,0,1" />
</StackPanel>
There is quite a bit of information in this code snippet, so let's unpack it piece by piece.
The top and bottom lines show the declaration of the StackPanel in the Xaml file. The StackPanel is declared with two attributes: a BackgroundColor (Beige) and an Orientation (which must be either Vertical or Horizontal).
There are many other attributes you can set, as will be true for nearly all the controls These, along with the methods are conveniently listed in the documentation,

Figure 1-7. Documentation Showing Stack Panel Members (Click to view full-size image)
By setting the Orientation to Vertical we are stacking its contents one on top of another rather than side by side.
Within the StackPanel, the four objects are declared, and the order of their declaration will determine the order in which they are stacked. Each is set with its TextAlignment property set to Left so that they will align, and each has its Margin property set. Let's dig just a bit deeper into the Margin property by looking up its definition in the documentation,
public Thickness Margin { get; set; }
The Margin property is actually an object of type Thickness. As noted earlier, when you are declaring a Thickness object in Xaml you may do so in one of three ways:
1. You may provide a double that will be the margin for the margin on all four sides (left, top, right, and bottom) uniformly around the object. Thus, you might write
<Button Content="Submit this information"
HorizontalAlignment="Left"
Margin="100" Height="30" Width="150" />
Thereby isolating the button with a margin of 100 on either side and above and below,

Figure 1-8. Button Margins
Notice that to accommodate the oversided margin, the width of the button was compromised!
The second way to declare a Thickness (and in this case, a Margin) is to provide the sum of the sides and the sum of the top and bottom (thus, the sides must be equal and the top and bottom must be equal,
<Button Content="Submit this information"
HorizontalAlignment="Left"
Margin="50,20" Height="30" Width="150" />
The effect of this declaration is that the left and right margins are 25, and the top and bottom margins are each 10.
Finally, you may declare each independently, as long as you do so in the required order:

Figure 1-9. Margins are a Thickness Object
That is: Left, Top, Right, Bottom; or in this case, the Left margin is 10, the Top margin is 2, the Right margin is 0 and the Bottom margin is 1.
Once the four controls are placed in the stack Panel, and aligned, the stack panel is responsible for their placement,

Figure 1-10. Stack Panel At Work
Notice that the StackPanel is responsible for its own background color, and for stacking its contents (the four controls) but each control is responsible for its own alignment and margins.
Horizontal Stack Panels
If we want to shift the stack panel to align all the controls into a single row, we'll want to make a few additional changes. Not all controls default to aligning in the same way (top, center or bottom) so we'll explicitly set their vertical alignment to "Center," just as we previously set their horizontal alignment to "Left". Let's also set the margins to provide a bit of space between each object as the default is to abut each object.
<StackPanel Background="Beige" Orientation="Vertical" >
<TextBlock Text="Your name?"
HorizontalAlignment="Left" Margin="10,2,0,1"/>
<TextBox Width="150" Height="30"
HorizontalAlignment="Left" Margin="10,2,0,1"/>
<Button Content="Submit this information"
HorizontalAlignment="Left"
Margin="10,2,0,1" Height="30" Width="150" />
<CheckBox Content="With Zing!" HorizontalAlignment="Left"
Margin="10,2,0,1" />
</StackPanel>
Note that I set the left margin on the text box to 5 (rather than 10) to bring it a bit closer to the TextBlock that serves as its label.

Figure 1-11. Stack Panel in Horizontal Orientation (Click to view full-size image)
Control Events and Event Handlers
In Silverlight 2 each class declares whether it is supported by managed code or not, by including (or not including) the x:Class attribute in its root element. These tutorials will assume you are working in managed code, and that this attribute is therefore present.
When you create a C# Silverlight application, this is placed for you, as shown here,
<UserControl x:Class="EasyGrid.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
Declaring Event Handlers
There are two ways to declare event handlers in Silverlight: in the Xaml file or in the code-behind. If you declare event handlers in Xaml you cannot add parameters. A typical event handler declaration in XAMl might look like this
<Canvas Loaded="Canvas_Loaded">
<Button x:Name="myButton" Content="Hello"
Canvas.Left="10" Canvas.Top="10" />
</Canvas>
Here I've declared a Canvas object and assigned an event handler named "Canvas_Loader" to the Loaded event (a pre-existing event common to all canvases that fires when the Canvas is loaded (created).
I also declare a button in the Xaml and set its content to Hello.
This code appears in Page.xaml. In the code behind file, Page.xaml.cs, I must now implement the event handler with the name I've promised to use,
private void Canvas_Loaded(object sender, RoutedEventArgs e)
{
theButton.Content = "Please Click Me";
}
The first thing to notice is that the name of the method is identical to that as declared in the Xaml. The second is that this method follows the pattern of all .NET event handlers: it returns void and takes two parameters: the first of type object (and containing a reference to the object that raised the event) and the second of type EventArgs or a type that derives from EventArgs; in this case RoutedEventArgs. We'll come back to RoutedEventArgs in just a moment.
The implementation is that when the Canvas is loaded it grabs the button declared in the Xaml file and changes its Content property from "Hello" to "Please push me",

Figure 1-12. Content Property Changed
Even in this incredibly simple example there are two important things to notice:
1. You did not have to declare myButton in the code behind; it was known simply by declaring it in the Xaml
2. The button adjusted its size to accommodate the larger string.
Declaring Event Handlers In Code
I admit it, I have a strong preference for declaring all event handlers in code. I believe it is better encapsulation, making for more scalable and more maintainable code. But this is a personal opinion.
In any case, if you want to declare your event handlers correctly in code, Visual Studio makes it very easy to do so. The most common way is to wire up the event handlers in the OnLoaded event handler, with that event (Loaded) wired up in the Page's constructor.
To see this, return to your previous code and remove the event handler from the Xaml. While you're there, add a check box as shown here,
<!-- <Canvas Loaded="Canvas_Loaded"> -->
<Canvas >
<Button x:Name="theButton" Content="I'm Indented!"
Canvas.Left="150" Canvas.Top="20" />
<CheckBox x:Name="RushOrder" Content="Rush"
Canvas.Left="50" Canvas.Top="20" FontSize="18" />
</Canvas>
Notice that the original Canvas is commented out, and replaced by a Canvas that does not have an event.
Save the Xaml file and open the code behind.
In the constructor, type Lo. Intellisense will pop up and offer to help you create the EventHandling code, landing on the event Loaded, which is exactly what you want. The tip (next to the Intellisence box) shows the type of the event.

Figure 1-13. Intellisense Helps Create Event Handler (Click to view full-size image)
We'll return to the fact that Loaded is a RoutedEventHandler shortly. Press tab to accept Loaded and type += to begin adding the delegate. (If delegates and events are new to you, you may want to read this article. It's a bit old, but still accurate. You can also read extensively about delegates and events in any book on .NET 3.5 or C# or VB.
Intellisense will walk you through each step of wiring up the event handler, and if you let it, will also create the stub of the event handler method, ultimately placing your cursor in the method which it prefills with an exception (in case you forget to add a meaningful implementation.
public Page()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
Delete the exception and register event handlers for the common events for your button (click) and your checkbox (Checked and Unchecked)
void Page_Loaded(object sender, RoutedEventArgs e)
{
theButton.Click +=new RoutedEventHandler(theButton_Click);
RushOrder.Checked += new RoutedEventHandler(RushOrder_Changed);
RushOrder.Unchecked +=new RoutedEventHandler(RushOrder_Change);
}
Be careful here, Intellisense will want to name the methods for Checked and Unchecked RushOrder_Checked and RushOrder_Unchecked respectively, but there is no need for two methods. We'll override that by typing in the name we want, RushOrder_Changed, which will cause both events to use a shared event handler.
In the shared event handler, we'll check the IsChecked status of the checkbox and if it is checked, we'll change its text to all upper case (just so we know the event handler is working).
void RushOrder_Changed(object sender, RoutedEventArgs e)
{
if (RushOrder.IsChecked == true)
{
RushOrder.Content = "RUSH";
}
else
{
RushOrder.Content = "Rush";
}
}
Note to C# programmers, we must write
if (RushOrder.IsChecked == true)
and not
if (RushOrder.IsChecked)
because IsChecked is of the new C# 3.0 type nullable bollean ( bool?) which indicates that it may have three states, not two: true, false or null.
RoutedEvents
Silverlight extends the CLR event handling mechanism (borrowing from WPF) with RoutedEvents.
Normal CLR events are ignored if no object subscribes to them. This presents a problem for WPF and Silverlight controls because many controls are created from numerous visual "pieces" such as text, curves, shapes and so forth. Moreover, the developer is allowed and encouraged to add one control onto (or into) another.
A button may have text and a rectangle along with a background and more. (Silverlight designers can be quite creative in mixing together visual elements). It would be tedious to force the developer to register a mouse event handler for the text of the button and for its rectangle and each of the other controls and objects that compose the button. Tedious, and error prone.
As an example, in a series of Silverlight 1.0 demonstrations I created some months ago, I used simple graphic primitives to create a "Little Green Man" out of a canvas, four ellipses and a path (a curved line). Let's add that to the XMAL file:
<Canvas x:Name="LGM" Canvas.Left="20" Canvas.Top="50" >
<Ellipse Canvas.Left="10"
Canvas.Top="10"
Width="160"
Height="160"
Fill="LimeGreen"
Stroke="Black" />
<Ellipse Canvas.Left="45"
Canvas.Top="50"
Width="25"
Height="25"
Fill="Black"
Stroke="Black" />
<Ellipse Canvas.Left="77.5"
x:Name="MiddleEye"
Canvas.Top="50"
Width="25"
Height="25"
Fill="Black"
Stroke="Black" />
<Ellipse Canvas.Left="110"
Canvas.Top="50"
Width="25"
Height="25"
Fill="Black"
Stroke="Black" />
<Path Data="M 50,100 A 30,30 900 0 0 130,100"
Stroke="Black"/>
</Canvas>
<!--End lgm-->
Here's what he looks like when you run the application...

Figure 1-14. Little Green Man
Cute, but not a control; but we can use him in a control if we can put him in the amazing shrinking machine. Let's make him small enough to fit in a button. This is easy to do; just divide every value in his dimensions by 5 (and then tinker when that doesn't work!) to make him a Very Little Green Man
<Canvas x:Name="VLGM" Canvas.Left="140" Canvas.Top="0" >
<Ellipse Canvas.Left="2"
Canvas.Top="2"
Width="32"
Height="32"
Fill="LimeGreen"
Stroke="Black" />
<Ellipse Canvas.Left="7"
Canvas.Top="10"
Width="5"
Height="5"
Fill="Black"
Stroke="Black" />
<Ellipse Canvas.Left="15"
x:Name="MiddleEye"
Canvas.Top="10"
Width="5"
Height="5"
Fill="Black"
Stroke="Black" />
<Ellipse Canvas.Left="22"
Canvas.Top="10"
Width="5"
Height="5"
Fill="Black"
Stroke="Black" />
<Path Data="M 10,20 A 6,6,180 0 0 26,20"
Stroke="Black"/>
</Canvas> <!--End vlgm-->
That makes him a lot more manageable
Figure 1-15. Very Little Green Man
To put him in a button we create a composite user control by combining a standard button and our VLGM into a canvas, which from then on we can treat as a single control,
<Canvas x:Name="CompositeButton"
Canvas.Left="150" Canvas.Top="10" >
<Button Content="Press the VLGM!"
Width="180" Height="40" />
<Canvas x:Name="VLGM" Canvas.Left="140" Canvas.Top="0" >
<Ellipse /> <!—Details removed to save space -->
<Ellipse /> <!—Details removed to save space -->
<Ellipse /> <!—Details removed to save space -->
<Ellipse /> <!—Details removed to save space -->
<Path />
</Canvas> <!--End vlgm-->
</Canvas> <!--end composite button-->
There are a lot of canvases here (and if I were doing this again, I might look at using StackPanels and Grids to simplify).
The first canvas is the new composite button that will contain a Silverlight button and our shrunken Very Little Green Man.
The second canvas (whose Canvas.Left and Canvas.Top positions is within the Composite Button) holds the parts of the VLGM: the ellipses and the path).

Figure 1-16. Composite Button with VLGM
As the developer of composite button, you certainly don't want to have to wire up separate event handlers for the internal button (which itself may be made up of text, a rectangle, etc.) and the VLGM (which we know is made up of four ellipses, a path and a canvas) . What is needed is a way to catch the click event on any of these objects and pass it up to the object that has the event handler (in this case, the Composite Button canvas.
How Routed Events Work: Event Bubbling
The defining characteristic of Routed Events is that each event is passed up the Interface Tree in a process known as bubbling (the events are like tiny bubbles rising up from the bottom)
If you click on the VLGM's middle eye the event is passed up the UI tree to the canvas that holds that eye, from there to the composite button where it is responded to.
However, most of the time, the event is "handled" at the control level and then the bubbling stops. Thus, if you click on the VLGM the event bubbles to the button, but if you click on a checkbox in side a button it is not bubbled up, because checkboxes are wired to handle their click events and then report the event as handled!
Implementing Dragging
To give our CompositeButton something to do, and to see that the RoutedEvents are actually working, let's implement the ability to drag the button around the Silverlight application (why not?)
Implementing the Event Handlers
Our goal is to be able to click on the CompositeButton and drag it around the browser. To do so we need to implement three event handlers:
- MouseLeftButonDown (pressing down on the left mouse button)
- MouseLeftButonDown (releasing the left mouse button)
- MouseMove (dragging with the left mouse button depressed)
The logic for MouseLeftButonDown is to get the current position of the mouse (and store it) and then to capture the mouse. Normally when you move off an object it stops sending MouseMove events, but in a Drag and Drop application we don't want it to stop sending MouseMove events until the button is released.
To keep track of the position of the mouse and whether we are tracking it, we'll create three private member variables. Since no methods of other classes will need access to these values, there is no advantage to making them properties.
private double beginX;
private double beginY;
private bool trackingMouseMove = false;
CompositeButton_MouseLeftButtonUp is passed the usual two parameters, but since this is a RoutedEvent you must remember that you cannot know the exact type of the sender (it could be a Canvas, a path, etc.). You can know, though that it is a FrameworkElement; the base class of all controls

Figure 1-17. The Control Object in the Object Hierarchy
The second parameter is of type MouseButtonEventArgs, filled with... well not that much useful information but one very useful method,

Figure 1-18. Documentation Excerpt on Mouse Button Event Args (Click to view full-size image)
With this we're all set.
void CompositeButton_MouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
{
beginX = e.GetPosition(null).X;
beginY = e.GetPosition(null).Y;
trackingMouseMove = true;
FrameworkElement fe = sender as FrameworkElement;
if (fe != null)
{
fe.CaptureMouse();
}
}
The GetPosition method passes in null, indicating that we do not want to provide a coordinate origin - that gives us the X and Y as an absolute position with respect to the surrounding canvas which is just what we want.
We set the Boolean value trackingMouseMove to true (we are now tracking the mouse) and we are ready to capture the mouse. Sender, however is an object and it can't Capture the Mouse. Moreover, as noted above, we don't necessarily know what type of control we have. We'll cast to the base type FrameworkElement and, being neurotically careful make sure the cast was successful (if not we'd get back null) and then call CaptureMouse. (A robust program would handle the condition where fe is null!)
The implementation of MouseLeftButtonUp is now straight-forward, we undo the work we just did,
void CompositeButton_MouseLeftButtonUp(
object sender, MouseButtonEventArgs e)
{
FrameworkElement fe =
sender as FrameworkElement;
fe.ReleaseMouseCapture();
trackingMouseMove = false;
}
NB: To save space, I've left out the if statement, and in this and future tutorials I'll often leave out the exceptions, testing and other error checking code necessary to build robust code but which is clutter when covering new concepts.
The real work is in MouseMove
void CompositeButton_MouseMove(object sender, MouseEventArgs e)
{
if (trackingMouseMove)
{
double currentX = e.GetPosition(null).X;
double currentY = e.GetPosition(null).Y;
FrameworkElement fe = sender as FrameworkElement;
double canvLeft =
Convert.ToDouble(fe.GetValue(Canvas.LeftProperty));
double canvTop =
Convert.ToDouble(fe.GetValue(Canvas.TopProperty));
double newLeft = canvLeft + currentX - beginX;
double newTop = canvTop + currentY - beginY;
fe.SetValue(Canvas.LeftProperty, newLeft);
fe.SetValue(Canvas.TopProperty, newTop);
beginX = currentX;
beginY = currentY;
}
}
We start by testing our Boolean to see if we're tracking MouseMove. If not, we can exit. If we are (and thus the left mouse button is down) we get the current mouse position just as we did before, and we get the sender as a FrameworkElement as we did before.
We need to ask the Framework element to give us its Attached Property Canvas.Left, and we do that using the GetValue method, which takes the LeftProperty property of the Canvas object as a parameter, which in turn we convert to a double and a assign to a temporary variable, then we do the same for Canvas.Top.
We now know the current position of the mouse, the Canvas.Left and Canvas.Top and the original position. With that we can compute where the object should move to.
We reach back into the object and set its Attached Properties, and then we clean up by setting the BeginX and BeginY values to the currentX and CurrentY and we're ready to handle the next MouseMove.
But we have a serious problem. The Button handles the MouseDown and MouseUp and does not pass it along to us. Thus, if you click on the button, your MouseDown and MouseUp methods will never be called. Since our LGM does not handle it, we can click on the LGM to move the button, but clicking on the button itself will not allow us to drag it (it will click and stay right where it is.
Understanding this distinction is quite important, so let me make it crystal clear: all the controls provided in the toolbox handle their own click method and Mouse and Keyboard methods, and then do not bubble them, so if you want to grab a mouse event you'll need to add to their content some object (which could of course have no visibility yet stretch over the entire control. We'll look at that in a future tutorial) .
When you run this application the three objects come up on the screen. Click on the LGM and the mouse down event handler kicks into effect. Drag and watch the button move. Lift your finger off the mouse and it stops moving

Figure 1-19. Drag and Drop in action
Creating Controls Dynamically
In Silverlight 2, all Xaml controls are isomorphic with CLR objects. That is, anything you can create in Xaml you can create in code.
Where you might write,
<Button x:Name="myButton" Content="Hello" />
You can also write
Button myButton = new Button();
myButton.Content = "Hello";
While it is possible to create all your controls and objects in code, best practices dictate that it is usually better to do so in Xaml. The most compelling reason is that Xaml is highly "toolable" - that is, it lends itself to round-trip modification in tools such as Visual Studio and Expression and thus is easier to scale, modify and maintain.
On the other hand, there are times that you can't know at design time which or how many objects you'll need, and the ability to create objects dynamically can be a fundamental requirement.
We can make a minor modification to our existing program to add another button on the user's request. Add the following button to the Xaml file,
<Canvas x:Name="myCanvas">
<Button x:Name="myButton" Content="Hello"
Canvas.Left="10" Canvas.Top="10"/>
<Button x:Name="Another" Content="Add Another"
Canvas.Left="10" Canvas.Top="50" />
<CheckBox x:Name="rushOrder" Content="Rush"
Canvas.Left="50" Canvas.Top="10" />
The effect is to add a button to the page with the words "Add Another." When the user clicks on this button, we want to add a button to the UI and we want that button to have its own size, position and behavior.
We do all of that in the code behind.
Creating a Button Dynamically
Save the .xaml file and open Page.xaml.cs
The first thing to do is to add an event handler for the new button,
Another.Click += new RoutedEventHandler(Another_Click);
And to add its implementation, in which you'll create a new button and set its properties,
void Another_Click(object sender, RoutedEventArgs e)
{
Button b = new Button();
b.Content = "I live!";
b.SetValue(Canvas.LeftProperty, 10.0);
b.SetValue(
Canvas.TopProperty,
this.newButtonPosition);
this.newButtonPosition += 30.0;
b.Width = 100;
b.Height = 20;
b.Click +=new RoutedEventHandler(new_button_click);
myCanvas.Children.Add(b);
}
Because the canvas's Left and Top are not actually properties of the Button (but are extended properties) you set them with the SetValue method, which takes two parameters. The first is the actual name of the property you want to set (Canvas.LeftProperty and Canvas.TopProperty) which is not difficult to find as Intellisense will supply it) and the second is the value (in this case a double).
Because I want to be able to click this button more than once, and I don't want the new buttons overwriting each other, I need a member variable to keep track of the top value,
private double newButtonPosition = 100.0;
After I set it, I can then increment it so the next button will fall below the previous,
b.SetValue(
Canvas.TopProperty,
this.newButtonPosition);
this.newButtonPosition += 30.0;
The result is very satisfying,

Figure 1-20. Adding Dynamic Buttons
The second thing to notice about the Button we are adding is that we are also adding an event handler registration,
b.Click +=new RoutedEventHandler(new_button_click);
This means that every button that is added (each of the three shown in Figure 1-8) is registered to call new_button_click when it is clicked. You'll need to write that event handler into your Page.xaml.cs file,
void new_button_click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
btn.Content = "Don't do that!";
btn.IsEnabled = false;
}
As the buttons are clicked, they change their message and become disabled,

Figure 1-21. Disabled Dynamic Buttons
Finally, none of this will work if you don't add the buttons to the page. In this case, however, you don't want to add them to LayoutRoot as their positioning is in terms of a specific canvas, so you'll add them to that canvas,
myCanvas.Children.Add(b);
When you run the program, they are members of that canvas, just as surely as if you had added them individually in the Xaml file.