User Controls: Usercontrol
User Controls: Usercontrol
UserControls are the basic unit of reusable Xaml and the code that goes with it. You can create
UserControls in many ways. One of the two most common ways is to create a new application
and let Blend or Visual Studio create them for you. This seems surprising until you look closely
at Page.xaml and App.xaml and realize that they are in fact UserControls.
I created an application called KeyboardControl and the very first line in Page.xaml is this:
<UserControl x:Class="KeyboardControl.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="600" Height="350">
namespace KeyboardControl
{
public partial class Page : UserControl
{
The second way to create UserControls is to explicitly add one to your application. If you right
click the project and choose Add®New Item, the dialog that comes up will offer a template with
Silverlight User Control as one of the options.
The UserControl that is created is exactly like Page.xaml except of course that it has whatever
name you give it.
You can add user controls to your application for a couple reasons, but the most common is to
encapsulate some functionality that you'd like to reuse; in this application or, less commonly, in
another.
The best way to see how this works is to create some useful functionality and then to put it into a
user control and reuse it.
The key to reusability is having something worth reusing. We'll start by recreating an enhanced
form first demonstrated by Karen Corby at Mix08 and used here with her permission and
encouragement. You can fill out this form by hand, but it also supports keyboard shortcuts;
specifically, Ctrl-M adds the address of Microsoft, and Ctrl-C adds the address of the Computer
History Museum in Mountainview California.
Figure 4-1. The Form Filled in by Pressing Control-C
This project will assume you've worked your way through the previous tutorials and thus will
progress quickly through
• Creating an application
• Adding controls and adding event handlers
• Using styles
Because setting up the form and the grid can be tedious, I've also included a starter application
(KeyboardStarter) with the source code.
So, to get started, fire up Visual Studio 2008 and create a new application called
KeyboardControl
The image above shows a text block with Home Address, and then what amounts to a grid with a
border and prompts on the left and text boxes on the right. That suggests that the First control
will be a stack panel so that we can easily stack one control on top of another, and within that
stack panel a Grid.
<UserControl x:Class="KeyboardControl.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="500" Height="500">
<StackPanel Background="White">
<TextBlock Text="Home Address" FontFamily="Verdana" FontSize="24"
HorizontalAlignment="Left" Margin="15,0,0,0"/>
Set the background color for the grid to a soft color (I personally like Bisque). While you're at it,
surround your Grid with a Black Border. Give your grid 5 rows plus top and borders of 10 and
two columns with left and right borders of 10 and a center padding of 10, as shown,
The grid will be filled with four prompts and four text boxes, but a quick look at the earlier
diagram shows that these are hand styled as was done in Beta 1. We will have an extensive
tutorial on the new and much improved Styling and Templating support in Beta 2 coming quite
soon, but the code shown here will still work. You can just copy and paste it in App.xaml within
the Application.Resources tags.
Each Style identifies its TargetType (e.g., Button or TextBlock) and then sets a value for each
property it wants to control the style of. We are creating only two styles, one for TextBlocks that
will be used as labels, and one for TextBoxes to gather data.
All the TextBlocks will be Bottom and Left aligned, and will have their text set to Verdana, size
18 and the text will be blue. These TextBlocks will also have a margin of 5 all around.
<Application.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockPrompt">
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Medium" />
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Margin" Value="5" />
</Style>
All the TextBoxes will set their font to Verdana, but at 18 point, bold black; also aligned bottom
and left. The TextBox itself ill be 250 by 30 and they too will set a margin of 5 all around.
</Application.Resources>
Rather than adding the style information piece by piece to the TextBlock we can now bind the
style information to the Style attribute, using the "key" to identify which style we want to use.
The line
Style="{StaticResource TextBlockPrompt}"
Reaches into App.xaml and finds the style resource whose key is TextBlockPrompt and assigns
all these values in one swell foop.
In the same way, we can assign the TextBox style to the associated text box.
<TextBox x:Name="Location"
Style="{StaticResource TextBoxStyle}"
Text ="Silverlight Central"
Grid.Row="2" Grid.Column="3" />
They make a matched set, and we can do the same for the other three controls as well.
<TextBox x:Name="Address1"
Style="{StaticResource TextBoxStyle}"
Text="100 Main Street"
Grid.Row="3" Grid.Column="3" />
<TextBox x:Name="Address2"
Style="{StaticResource TextBoxStyle}"
Text="Apartment 100"
Grid.Row="4" Grid.Column="3" />
<TextBox x:Name="City"
Style="{StaticResource TextBoxStyle}"
Text="Boston, MA 01001"
Grid.Row="5" Grid.Column="3"/>
Notice that the Text for each of the TextBox controls is hard coded and displayed as coded when
you run the application,
Figure 4-2. The Form with Hard-wired values
As discussed in the Tutorial on Data Binding one powerful way to bind the data that will fill the
address to data that you might persist in, for example, a database or an XML file or any other
storage, is by using a business object to mediate between your User Interface (the Silverlight
application) and the storage.
Let's create an address object that will map to the data we wish to display (though a typical
business object will probably not be so tightly coupled to a particular UI page). We will do with
address exactly what we did with the book object in that tutorial. Rather than making you wade
through all that code, I'll simply provide the Properties and their underlying member variables in
the next table:
The class structure is very similar to what you saw in the tutorial on data binding,
using System.Collections.Generic;
using System.ComponentModel;
namespace KeyboardControl
{
public class Address : INotifyPropertyChanged
{
With each of the properties providing a backing variable, a getter and a setter that also calls the
notification event.
Once you've filled in all the public properties you are ready to replace the hard coded Text Block
values with the data bound values,
<TextBox x:Name="Location"
Style="{StaticResource TextBoxStyle}"
Text ="{Binding Location, Mode=TwoWay }"
Grid.Row="2" Grid.Column="3" />
<TextBox x:Name="Address1"
Style="{StaticResource TextBoxStyle}"
Text ="{Binding Address1, Mode=TwoWay }"
Grid.Row="3" Grid.Column="3" />
<TextBox x:Name="Address2"
Style="{StaticResource TextBoxStyle}"
Text ="{Binding Address2, Mode=TwoWay }"
Grid.Row="4" Grid.Column="3" />
<TextBox x:Name="City"
Style="{StaticResource TextBoxStyle}"
Text ="{Binding City, Mode=TwoWay }"
Grid.Row="5" Grid.Column="3"/>
Let's review what we have: a "form" that prompts for address information, and an Address
object that can either hold or provide that information.
Note that the "form" is implemented as the contents of the Grid whose name is "Address" and
which contains the four TextBlocks and the four TextBoxes.
What we'd like to add is the ability for the form itself to respond to two keyboard shortcuts.
When we press Control-M we'd like the form to be filled in with the address information for
Microsoft, and when we press Control-C we'd like to fill in the address of the Computer History
Museum
Figure 4-3. The Computer History Museum Building
Keyboard Events
To accomplish this, we'll respond to keyboard events received by the stack panel: specifically the
KeyDown event.
The Silverlight Help files document that the KeyDown event is a bubbling event (see Tutorial
#1 for a full explanation of bubbling).
We can start simple and respond to any keyboard event by filling the form with the Microsoft
address. We'll give the class a private Address object which we'll allocate memory for in the
constructor. We'll also handle the standard Loaded event that fires when the page is loaded.
In Page_Loaded we want to create an event handler for KeyDown when any keydown event is
registered on any control within the grid, which you'll remember we named AddressGrid in
Page.xaml like this,
<Grid x:Name="AddressGrid" Background="Bisque" >
When Page.xaml is saved, that identifier is immediately available in the code behind, and we can
access its properties and events, including its KeyDown event,
Visual Studio 2008 will offer to create the shell of an event handler for us, which is just what we
want. For now, we'll respond to the KeyDown indiscriminately; whatever key is pressed, we'll
fill in Microsoft's address.
This approach is called by various names, depending on how you feel about it:
I'm a big believer in successive approximation, by changing fewer things between test runs, I
have fewer things to look at when it doesn't work.
Note that we end the event by setting the DataContext of the page to the Address object we just
populated. That has the effect of providing a specific object for the controls to bind to. When you
run this application nothing happens. Click inside any of the four text boxes, however, and then
press any key at all and the address is filled in. The cleanest way to do this is to press the shift
key!
Clearly this isn't quite cooked. We want to fill in the Microsoft Address on Control-M, the
Computer Museum's address on Control-C. A small revision to the event handler is needed,
Bring up the application, anywhere in the form, and press Control-C; then Control-M and then
Control-C. Fun, eh?
By setting a break point where the key is examined, you can actually watch the test for the
Control-C combination; either hovering over the values, or looking at the Watch (or
QuickWatch) window,
User Control
This is, arguably, useful. In fact, we might want to have a Home Address, a Work Address and a
Billing Address, and it might be nice to have the control-key work for all three. Thus, we have
two choices.
1. Duplicate the xaml and code behind for each instance (home, work, billing)
2. Factor out the common xaml and supporting code into a control
I won't waste your time hammering on why we'll choose #2; if you've come this far you have a
visceral revulsion at the idea of choice #1 and are eager to get on to seeing how you create the
UserControl.
You begin, no surprise, by right clicking on the project and choosing Add. Within the templates
section of the dialog box choose Silverlight User Control. Name your new control Address.xaml
• Address.xaml
• Address.xaml.cs
Address.xaml will look amazingly familiar when you first open it.
<UserControl x:Class="KeyboardFun.Address"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
It is, essentially, the same as Page.xaml, except the names have been changed to protect the
innocent namespace.
Implementation
Return to Page.xaml and scoop out the Border and everything within it. The simplest way to do
this is to collapse the Border control (if outlining mode is off in Visual Studio 2008 you can
easily turn it on from the Edit menu when the design or code window has focus,
Collapse the Border and then use Control-X to cut it from its current position, and Control-V to
paste it into the new .xaml file, replacing the grid that was placed there by Visual Studio
2008
Notice that your control is in place but a bit narrow. Delete the Width and Height attributes from
the outer User Control,
<UserControl x:Class="UserControlDemo.AddressUserControl"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
> <!--no specific size-->
<Border BorderBrush="Black" BorderThickness="1" Margin="15">
As soon as you delete these the control will be centered and it will expand to fit the controls,
Figure 4-10. The new user control auto-sized
Adding Code
That's it for creating the User Control, but it isn't of much value if you don't place it back into
your Page.xaml file. Here's how.
xmlns:jl="clr-namespace:UserControlDemo"
3. You are now ready to substitute the User control for all the contents of the Border in
Page.xaml. If you've not deleted Border already do so now, and replace with your control, just as
you might place any other control into the StackPanel,
Let's add one more of our user controls to the StackPanel and change the prompt on the first, so
that it looks like this,
<UserControl x:Class="UserControlDemo.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:jl="clr-namespace:UserControlDemo"
Width="600" Height="500">
<StackPanel Background="White">
<TextBlock Text="Event Address" FontFamily="Verdana" FontSize="24"
HorizontalAlignment="Left" Margin="15,0,0,0"/>
<jl:AddressUserControl x:Name="HomeAddress" />
Note that adding a second instance of the AddressUserControl requires only making sure they
have different names. Before you run the program, take a peek at Page.xaml.cs,
using System.Windows.Controls;
namespace UserControlDemo
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
}
}
All the logic has been exported and encapsulated in the User Control. You can add 2 (or 20)
Address User Controls to your UI and add no code whatsoever. Yet, when you run the program,
each works independently, and each supports the Control-keys as implemented,
Figure 4-12. Two instances of one user control
I will follow with a tutorial on Custom Controls, but there are a few more fundamental topics I
want to be sure to cover first.
Note, the source code for this tutorial comes in three parts:
1. KeyboardStarter starts you off with a grid and the basic controls and styles you already
know about
2. KeyboardControl is the interim application with the KeyDown event handler
3. UserControlDemo is the final product with the KeyDown event handling logic factored
out into a User control.