CHAPTER 1 ■ INTRODUCING SILVERLIGHT
26
<img src="
alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
<iframe id="_sl_historyFrame"
style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>
</div>
</body>
</html>
The key detail is the <div> element that represents the Silverlight content region. It
contains an <object> element that loads the Silverlight plug-in. The <object> element includes
four key attributes. You won’t change the data and type attributes–they indicate that the
<object> element represents a Silverlight content region using version 2 or later. However, you
may want to modify the height and width attributes, which determine the dimensions of the
Silverlight content region, as described next.
■ Note Be cautious about changing seemingly trivial details in the HTML test page. Some minor quirks are
required to ensure compatibility with certain browsers. For example, the comma at the end of the data attribute in
the <object> element ensures Firefox support. The invisible <iframe> at the bottom of the Silverlight <div> allows
navigation to work with Safari. As a general guideline, the only test page content you should change are the
width and height settings, the list of parameters, and the alternate content.
CHANGING THE TEST PAGE
If you’re using an ASP.NET website, the test page is generated once, when the ASP.NET website
is first created. As a result, you can modify the HTML page without worrying that your changes
will be overwritten.
If you’re using a stand-alone project without an ASP.NET website, Visual Studio generates
the test page each time you run the project. As a result, any changes you make to it will be
discarded. If you want to customize the test page, the easiest solution is to create a new test
attributes from the <UserControl> start tag. That way, the page will be sized to match the
Silverlight content region, which in turn is sized to fit the browser window, and your Silverlight
content will always fit itself into the currently available space.
To get a better understanding of the actual dimensions of the Silverlight content
region, you can add a border around it by adding a simple style rule to the <div>, like this:
<div id="silverlightControlHost" style="border: 1px red solid">
You’ll create resizable and scalable Silverlight pages in Chapter 3, when you explore
layout in more detail.
Silverlight Parameters
The <object> element contains a series of <param> elements that specify additional options to
the Silverlight plug-in.
Table 1-1 lists some of basic the parameters that you can use. You’ll learn about many
other specialized parameters in examples throughout this book, as you delve into features like
HTML access, splash screens, transparency, and animation.
Table 1-1. Basic Parameters for the Silverlight Plug-In
Name Value
source A URI that points to the XAP file for your Silverlight
application. This parameter is required.
CHAPTER 1 ■ INTRODUCING SILVERLIGHT
28
Name Value
onError A JavaScript event handler that’s triggered when a
unhandled error occurs in the Silverlight plug-in or in
your code. The onError event handler is also called if
the user has Silverlight installed but doesn’t meet the
minRuntimeVersion parameter.
background The color that’s used to paint the background of the
Silverlight content region, behind any content that
29
Name Value
windowless A Boolean that specifies whether the plug-in renders
in windowed mode (the default) or windowless mode.
If you set this true, the HTML content underneath
your Silverlight content region can show through. This
is ideal if you’re planning to create a shaped Silverligh
t
control that integrates with HTML content, and you’ll
see how to use it in Chapter 14.
onSourceDownloadProgressChanged A JavaScript event handler that’s triggered when a
piece of the XAP file has been downloaded. You can
use this event handler to build a startup progress bar,
as in Chapter 6
onSourceDownloadComplete A JavaScript event handler that’s triggered when the
entire XAP file has been downloaded.
onLoad A JavaScript event handler that’s triggered when the
markup in the XAP file has been processed and your
first page has been loaded.
onResize A JavaScript event handler that’s triggered when the
size of a Silverlight content region has changed.
Alternative Content
The <div> element also has some HTML markup that will be shown if the <object> tag isn’t
understood or the plug-in isn’t available. In the standard test page, this markup consists of a
Get Silverlight picture, which is wrapped in a hyperlink that, when clicked, takes the user to the
Silverlight download page.
<a href="
style="text-decoration:none">
First, disable the automatic upgrading process by setting the autoUpgrade parameter
to false:
<param name="autoUpgrade" value="false" />
Then, check for the version error code in the onSilverlightError function in the test
page. If you detect a version problem, you can then use JavaScript to alter the content of the
<div> element that holds the Silverlight plug-in. Swap in a more meaningful graphic that clearly
advertises your application, along with the download link for the correct version of Silverlight.
function onSilverlightError(sender, args) {
if (args.ErrorCode == 8001)
{
// Find the Silverlight content region.
var hostContainer = document.getElementById("silverlightControlHost");
// Change the content. You can supply any HTML here.
hostContainer.innerHTML = " ";
}
// (Deal with other types of errors here.)
}
To test your code, just set the minRuntimeVersion parameter absurdly high:
<param name="minRuntimeVersion" value="5" />
The Mark of the Web
One of the stranger details in the HTML test page is the following comment, which appears in
the second line:
<! saved from url=(0014)about:internet >
Although this comment appears to be little more than an automatically generated
stamp that the browser ignores, it actually has an effect on the way you debug your application.
CHAPTER 1 ■ INTRODUCING SILVERLIGHT
peered behind the scenes to explore how a Silverlight application is compiled and deployed.
In the following chapters, you’ll learn much more about the full capabilities of the
Silverlight platform. Sometimes, you might need to remind yourself that you’re coding inside a
lightweight browser-hosted framework, because much of Silverlight coding feels like the full
.NET platform, despite the fact that it’s built on only a few megabytes of compressed code. Out
of all of Silverlight’s many features, its ability to pack a miniature modern programming
framework into a slim 5-MB download is surely its most impressive. 33
CHAPTER 2
■ ■ ■
XAML
XAML (short for Extensible Application Markup Language and pronounced zammel) is a
markup language used to instantiate .NET objects. Although XAML is a technology that can be
applied to many different problem domains, it was initially designed as a part of Windows
Presentation Foundation (WPF), where it allows Windows developers to construct rich user
interfaces. You use the same standard to build user interfaces for Silverlight applications.
Conceptually, XAML plays a role that’s a lot like HTML, and is even closer to its stricter
cousin, XHTML. XHTML allows you to define the elements that make up an ordinary web page.
Similarly, XAML allows you to define the elements that make up a XAML content region. To
manipulate XHTML elements, you can use client-side JavaScript. To manipulate XAML
elements, you write client-side C# code. Finally, XAML and XHTML share many of the same
syntax conventions. Like XHTML, XAML is an XML-based language that consists of elements
that can be nested in any arrangement you like.
In this chapter, you’ll get a detailed introduction to XAML and consider a simple
single-page application. Once you understand the broad rules of XAML, you’ll know what is and
isn’t possible in a Silverlight user interface–and how to make changes by hand. By exploring
the tags in a Silverlight XAML document, you’ll also learn more about the object model that
underpins Silverlight user interfaces and get ready for the deeper exploration to come.
1 <UserControl x:Class="SilverlightApplication1.MainPage"
2 xmlns="
3 xmlns:x="
4 xmlns:d="
5 xmlns:mc="
6 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
7
8 <Grid x:Name="LayoutRoot">
9 </Grid>
10 </UserControl>
This document includes only two elements–the top-level UserControl element, which
wraps all the Silverlight content on the page, and the Grid, in which you can place all your
elements.
As in all XML documents, there can only be one top-level element. In the previous
example, that means that as soon as you close the UserControl element with the
</UserControl> tag, you end the document. No more content can follow.
XAML Namespaces
When you use an element like <UserControl> in a XAML file, the Silverlight parser recognizes
that you want to create an instance of the UserControl class. However, it doesn’t necessarily
CHAPTER 2 ■ XAML
35
know what UserControl class to use. After all, even if the Silverlight namespaces only include a
single class with that name, there’s no guarantee that you won’t create a similarly named class
of your own. Clearly, you need a way to indicate the Silverlight namespace information in order
to use an element.
In Silverlight, classes are resolved by mapping XML namespaces to Silverlight
namespaces. In the sample document shown earlier, four namespaces are defined:
2 xmlns=" CHAPTER 2 ■ XAML
36
XML NAMESPACES AND SILVERLIGHT NAMESPACES
The XML namespace name doesn’t correspond to a single Silverlight namespace. Instead, all the
Silverlight namespaces share the same XML namespace. There are a couple of reasons the
creators of XAML chose this design. By convention, XML namespaces are often URIs (as they are
here). These URIs look like they point to a location on the Web, but they don’t. The URI format is
used because it makes it unlikely that different organizations will inadvertently create different
XML-based languages with the same namespace. Because the domain schemas.microsoft.com
is owned by Microsoft, only Microsoft will use it in an XML namespace name.
The other reason that there isn’t a one-to-one mapping between the XML namespaces
used in XAML and Silverlight namespaces is because it would significantly complicate your XAML
documents. If each Silverlight namespace had a different XML namespace, you’d need to specify
the right namespace for each and every control you use, which would quickly get messy.
Instead, the creators of Silverlight chose to map all the Silverlight namespaces that include user
interface elements to a single XML namespace. This works because within the different
Silverlight namespaces, no two classes share the same name.
Design Namespaces
Along with these core namespaces are too more specialized namespaces, neither of which is
essential:
• is the XAML
compatibility namespace. You can use it to tell the XAML parser what information
must to process and what information to ignore.
• is a namespace reserved for
design-specific XAML features that are supported in Expression Blend (and now
• The XML namespace prefix: You’ll use the namespace prefix to refer to the namespace in
your XAML page. In this example, that’s w, although you can choose anything you want
that doesn’t conflict with another namespace prefix.
• The .NET namespace: In this case, the classes are located in the Widgets namespace. If
you have classes that you want to use in multiple namespaces, you can map them to
different XML namespaces or to the same XML namespace (as long as there aren’t any
conflicting class names).
• The assembly: In this case, the classes are part of the WidgetLibrary.dll assembly. (You
don’t include the .dll extension when naming the assembly.) Silverlight will look for that
assembly in the same XAP package where your project assembly is placed.
■ Note Remember, Silverlight uses a lean, stripped-down version of the CLR. For that reason, a Silverlight
application can’t use a full .NET class library assembly. Instead, it needs to use a Silverlight class library. You
can easily create a Silverlight class library in Visual Studio by choosing the Silverlight Class Library project
template.
If you want to use a custom control that’s located in the current application, you can
omit the assembly part of the namespace mapping, as shown here:
xmlns:w="clr-namespace:Widgets"
Once you’ve mapped your .NET namespace to an XML namespace, you can use it
anywhere in your XAML document. For example, if the Widgets namespace contains a control
named HotButton, you could create an instance like this:
<w:HotButton Text="Click Me!" Click="DoSomething"></w:HotButton>
CHAPTER 2 ■ XAML
38
You’ll use this technique throughout this book to access controls in the Silverlight add-
on assemblies and the Silverlight Toolkit.
The Code-Behind Class
XAML allows you to construct a user interface, but in order to make a functioning application,
public MainPage()
{
InitializeComponent();
}
}
}
Currently, the MainPage class code doesn’t include any real functionality. However, it
does include one important detail–the default constructor, which calls InitializeComponent()
when you create an instance of the class. This parses your markup, creates the corresponding
objects, sets their properties, and attaches any event handlers you’ve defined.
CHAPTER 2 ■ XAML
39
■ Note The InitializeComponent() method plays a key role in Silverlight content. For that reason, you should
never delete the InitializeComponent() call from the constructor. Similarly, if you add another constructor to your
page, make sure it also calls InitializeComponent().
Naming Elements
There’s one more detail to consider. In your code-behind class, you’ll often want to manipulate
elements programmatically. For example, you might want to read or change properties or
attach and detach event handlers on the fly. To make this possible, the control must include a
XAML Name attribute. In the previous example, the Grid control already includes the Name
attribute, so you can manipulate it in your code-behind file.
6 <Grid x:Name="LayoutRoot">
7 </Grid>
The Name attribute tells the XAML parser to add a field like this to the automatically
generated portion of the MainPage class:
private System.Windows.Controls.Grid LayoutRoot;
</Grid.RowDefinitions>
<TextBox x:Name="txtQuestion" >
</TextBox>
<Button x:Name="cmdAnswer" >
</Button>
<
TextBox x:Name="txtAnswer" >
</TextBox>
</Grid>
</UserControl>
CHAPTER 2 ■ XAML
41
In the following sections, you’ll explore the parts of this document–and learn the
syntax of XAML along the way.
Simple Properties and Type Converters
As you’ve already seen, the attributes of an XML element set the properties of the
corresponding Silverlight object. For example, the text boxes in the eight ball example configure
the alignment, margin, and font:
<TextBox x:Name="txtQuestion"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
FontFamily="Verdana" FontSize="24" Foreground="Green" >
In order for this to work, the System.Windows.Controls.TextBox class must provide the
following properties: VerticalAlignment, HorizontalAlignment, FontFamily, FontSize, and
Foreground. You’ll learn the specific meaning for each of these properties in the following
TypeConverter(typeof(BrushConverter)) attribute declaration.
3. If there’s no associated type converter on the property declaration or the class
declaration, the XAML parser generates an error.
This system is simple but flexible. If you set a type converter at the class level, that
converter applies to every property that uses that class. On the other hand, if you want to fine-
tune the way type conversion works for a particular property, you can use the TypeConverter
attribute on the property declaration instead.
It’s technically possible to use type converters in code, but the syntax is a bit
convoluted. It’s almost always better to set a property directly–not only is it faster but it also
avoids potential errors from mistyping strings, which won’t be caught until runtime. This
problem doesn’t affect XAML, because the XAML is parsed and validated at compile time.
■ Note XAML, like all XML-based languages, is case-sensitive. That means you can’t substitute <button> for
<Button>. However, type converters usually aren’t case-sensitive, which means both Foreground="White"
and
Foreground="white" have the same result.
Complex Properties
As handy as type converters are, they aren’t practical for all scenarios. For example, some
properties are full-fledged objects with their own set of properties. Although it’s possible to
create a string representation that the type converter could use, that syntax might be difficult to
use and prone to error.
Fortunately, XAML provides another option: property-element syntax. With property-
element syntax, you add a child element with a name in the form Parent.PropertyName. For
example, the Grid has a Background property that allows you to supply a brush that’s used to
paint the area behind the elements. If you want to use a complex brush–one more advanced
than a solid color fill–you’ll need to add a child tag named Grid.Background, as shown here:
<Grid x:Name="grid1">
<Grid.Background>
</Grid.Background>
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
Finally, you can fill the GradientStops collection with a series of GradientStop objects.
Each GradientStop object has an Offset and Color property. You can supply these two values
using the ordinary property-attribute syntax:
<Grid x:Name="grid1">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
<GradientStop Offset="1.00" Color="Purple" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
■ Note You can use property-element syntax for any property. But usually you’ll use the simpler property-
attribute approach if the property has a suitable type converter. Doing so results in more compact code.
CHAPTER 2 ■ XAML
44
Any set of XAML tags can be replaced with a set of code statements that performs the
Attached properties always use a two-part name in this form:
DefiningType.PropertyName. This two-part naming syntax allows the XAML parser to
distinguish between a normal property and an attached property.
In the eight ball example, attached properties allow the individual elements to place
themselves on separate rows in the (invisible) grid:
<TextBox Grid.Row="0">
</TextBox>
<Button Grid.Row="1">
</Button>
<TextBox Grid.Row="2">
</TextBox>
Attached properties aren’t really properties at all. They’re actually translated into
method calls. The XAML parser calls the static method that has this form:
DefiningType.SetPropertyName(). For example, in the previous XAML snippet, the defining type
is the Grid class, and the property is Row, so the parser calls Grid.SetRow().
CHAPTER 2 ■ XAML
45
When calling SetPropertyName(), the parser passes two parameters: the object that’s
being modified, and the property value that’s specified. For example, when you set the
Grid.Row property on the TextBox control, the XAML parser executes this code:
Grid.SetRow(txtQuestion, 0);
This pattern (calling a static method of the defining type) is a convenience that
conceals what’s really taking place. To the casual eye, this code implies that the row number is
stored in the Grid object. However, the row number is actually stored in the object that it
applies to–in this case, the TextBox object.
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
<GradientStop Offset="1.00" Color="Purple" />
</LinearGradientBrush.GradientStops>
CHAPTER 2 ■ XAML
46
</LinearGradientBrush>
The XAML parser recognizes the LinearGradientBrush.GradientStops element is a
complex property because it includes a period. However, it needs to process the tags inside (the
three GradientStop elements) a little differently. In this case, the parser recognizes that the
GradientStops property returns a GradientStopCollection object, and the
GradientStopCollection implements the IList interface. Thus, it assumes (quite rightly) that
each GradientStop should be added to the collection using the IList.Add() method:
GradientStop gradientStop1 = new GradientStop();
gradientStop1.Offset = 0;
gradientStop1.Color = Colors.Yellow;
IList list = brush.GradientStops;
list.Add(gradientStop1);
Some properties might support more than one type of collection. In this case, you
need to add a tag that specifies the collection class, like this:
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.00" Color="Yellow" />
<GradientStop Offset="0.50" Color="White" />
This indicates that any nested elements should be used to set the Children property.
The XAML parser treats the content property differently depending on whether or not it’s a
collection property (in which case it implements the IList or IDictionary interface). Because the
Panel.Children property returns a UIElementCollection, and because UIElementCollection
implements IList, the parser uses the IList.Add() method to add nested content to the grid.
In other words, when the XAML parser meets the previous markup, it creates an instance of
each nested element and passes it to the Grid using the Grid.Children.Add() method:
txtQuestion = new TextBox();
grid1.Children.Add(txtQuestion);
cmdAnswer = new Button();
grid1.Children.Add(cmdAnswer);
txtAnswer = new TextBox();
grid1.Children.Add(txtAnswer);
What happens next depends entirely on how the control implements the content
property. The Grid displays all the elements it holds in an invisible layout of rows and columns,
as you’ll see in Chapter 3.
BROWSING NESTED ELEMENTS WITH VISUALTREEHELPER
Silverlight provides a VisualTreeHelper class that allows you to walk through the hierarchy
elements. The VisualTreeHelper class provides three static methods for this purpose: GetParent(),
which returns the element that contains a specified element; GetChildrenCount(), which indicates
how many elements are nested inside the specified element; and GetChild(),which retrieves one
of the nested elements, by its index number position.
The advantage of VisualTreeHelper is that it works in a generic way that supports all
Silverlight elements, no matter what content model they use. For example, you may know that
Here’s how to dissect the entire current page:
Clear(this);
Events
So far, all the attributes you’ve seen map to properties. However, attributes can also be used to
attach event handlers. The syntax for this is EventName="EventHandlerMethodName".
For example, the Button control provides a Click event. You can attach an event
handler like this:
<Button Click="cmdAnswer_Click">
This assumes that there is a method with the name cmdAnswer_Click in the code-
behind class. The event handler must have the correct signature (that is, it must match the
delegate for the Click event). Here’s the method that does the trick:
private void cmdAnswer_Click(object sender, RoutedEventArgs e)
{
AnswerGenerator generator = new AnswerGenerator();
txtAnswer.Text = generator.GetRandomAnswer(txtQuestion.Text);
}
In many situations, you’ll use attributes to set properties and attach event handlers on
the same element. Silverlight always follows the same sequence: first it sets the Name property
(if set), then it attaches any event handlers, and lastly it sets the properties. This means that any
event handlers that respond to property changes will fire when the property is set for the first
time.
CHAPTER 2 ■ XAML
49
The Full Eight Ball Example
Now that you’ve considered the fundamentals of XAML, you know enough to walk through the
definition for the page in Figure 2-1. Here’s the complete XAML markup:
<UserControl x:Class="EightBall.MainPage"
<GradientStop Offset="1.00" Color="Purple" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
</Window>
Remember, you probably won’t write the XAML for a graphically rich user interface by
hand–doing so would be unbearably tedious. However, you might have good reason to edit the
XAML code to make a change that would be awkward to accomplish in the designer. You might
also find yourself reviewing XAML to get a better idea of how a page works.
CHAPTER 2 ■ XAML
50
XAML Resources
Silverlight includes a resource system that integrates closely with XAML. Using resources, you
can:
• Create nonvisual objects: This is useful if other elements use these objects. For
example, you could create a data object as a resource and then use data binding to
display its information in several elements.
• Reuse objects: Once you define a resource, several elements can draw on it. For
example, you can define a single brush that’s used to color in several shapes. Later in
this book, you’ll use resources to define styles and templates that are reused among
elements.
• Centralize details: Sometimes, it’s easier to pull frequently changed information into
one place (a resources section) rather than scatter it through a complex markup file,
where it’s more difficult to track down and change.
The resource system shouldn’t be confused with assembly resources, which are blocks
of data that you can embed in your compiled Silverlight assembly. For example, the XAML files
you add to your project are embedded as assembly resources. You’ll learn more about assembly