Silverlight 4.0

    
Introduction

Silverlight enables development of the next generation of Microsoft .NET-based media experiences and rich interactive applications (RIAs) for the Web. Silverlight is delivered as a cross-platform and cross-browser plug-in that exposes a programming framework and features that are a subset of the .NET Framework and Windows Presentation Foundation (WPF).

Silverlight System Requirements
With any web-centric technology, it’s keenly important to have compatibility with the widest possible range of computers and devices. Although Silverlight is still evolving, it’s clearly stated
mandate is to “support all major browsers on Mac OS X and Windows.” Currently, Silverlight’s cross-browser compatibility stacks up fairly well:

Windows computers: Silverlight works on PCs with Windows 7, Windows Vista, and Windows XP. The minimum browser versions that Silverlight supports are Internet Explorer 6, Firefox 1.5, and Google Chrome 4.0. Silverlight will also work in Windows 2000, but only with Internet Explorer 6. Other browsers, such as Opera and Safari (for Windows), aren’t currently supported.

Mac computers: Silverlight works on Mac computers with OS X 10.4.8 or newer, provided they have Intel hardware (as opposed to the older PowerPC hardware). The minimum browser versions that Silverlight supports are Firefox 2 and Safari 3.

Linux computers: Although Silverlight 4 doesn’t currently work on Linux, the Mono team has created an open source Linux implementation of Silverlight 1 and Silverlight 2, and implementations of Silverlight 3 and Silverlight 4 are planned for the future. This project is known as Moonlight, and it’s being developed with key support from Microsoft.
In response to the overwhelming developer community anticipation for the arrival of Silverlight, many developers and companies have become early adopters of the technology.
Some example sites are listed below:
  • World Series of Poker
  • Discovery Channel
  • The Emmys
  • Home Shopping Network (HSN)
  • World Wrestling Entertainment (WWE)
  • Fox
  • XBOX 360
  • Netflix - uses Silverlight to allow subscribers to instantly watch movies on their PCs or Intel-based Macs.
Many of the published early adopter applications are featured in the Silverlight.net showcase.
The .NET Framework
Microsoft introduced the .NET Framework in 2000 as a new approach to software development. The .NET Framework borrowed ideas from the best practices in the software industry as well as brought new ideas to the table in an effort to meet developer needs and requests.
Virtually all programming languages manage data at some point. The primary reason that communication between applications created using C++, Visual Basic, Visual FoxPro, and other languages was difficult was because each language stored data being managed in a unique set of data types. For example, an integer in one language may not represent an integer in another language. Data needed to be converted to common data types to communicate between languages.
The .NET Framework introduced a common set of data types (the Common Type System) that is used by all .NET-compliant languages (C++, Visual Basic, C#, etc). Thus all languages can easily intercommunicate. Furthermore, all .NET-compliant languages render a common result when compiling code, Microsoft Intermediate Language (MSIL).(see footnote) MSIL can be deployed to any platform running the Common Language Runtime (CLR). Currently, the CLR is only available for Microsoft Windows although an open source version of the CLR was created for Linux (called the Mono Project). Code written by using the .NET Framework is compiled instead of interpreted resulting in much better performance than Java and competing technologies.
Microsoft took the Web development industry by storm with their .NET upgrade to ASP. ASP.NET put a new face on Web development through compiled code architecture and improved state management and it provides access to the full functionality of the .NET Framework. ASP.NET is built around XML, supports the latest Web development standards, and allows for the creation of advanced Web Services.
The .NET Framework also provides improved data access and database integration through ADO.NET. For more information, see MSDN.
There are many more features and benefits of the .NET Framework than those mentioned here. The .NET Framework has become the leading software development environment available.
Introducing Silverlight
What's New in the .NET Framework
As of the writing of this course, version 3.5 of the .NET Framework has been released. Version 3.5 includes features that encompass all facets of Windows, Web, and network development:
  • Includes just under 10,000 classes, methods, and properties.
  • Complies with the latest Web development standards.
  • Introduces revolutionary technologies used in Windows Vista development, rich media and user experiences, workflow management, security and authorization, and complete distributed communication protocols.
The .NET Framework can also be fully extended by developers to create custom classes and types. The functionality of the .NET Framework spans the server, the workstation, and the Web. The four primary additions to the .NET Framework as of version 3.0 are:
  1. Windows Presentation Foundation (WPF)
  2. Windows Communication Foundation (WCF)
  3. Windows Workflow Foundation (WF)
  4. CardSpace
Windows Presentation Foundation (WPF)
WPF is used to develop elaborate user interfaces like those that adorn Windows Vista and managed advanced media streaming and integration. WPF is a complete revamp of Windows Forms so that user interface, graphic, and media development is now designed around the .NET Framework.
Windows Communication Foundation (WCF)
WCF encompasses the ASP.NET Web Services and .NET remoting functionality that was contained in the .NET Framework 2.0 as well as new communication technologies.
Windows Workflow Foundation (WF)
WF is used to model complex workflow processes.
CardSpace
CardSpace is the embodiment of new security and user authorization functionality.
ASP.NET AJAX
ASP.NET AJAX was developed to improve performance in the browser by making post backs and calls between the browser and server asynchronously. ASP.NET AJAX uses new built-in types and controls and JavaScript.
Both ASP.NET and ASP.NET AJAX are heavily dependent upon the ASP.NET page event life cycle, are tightly coupled to the server, and have a tough time competing with advanced, media-rich plug-in solutions such as Adobe Flash. Additionally, it is difficult to create Web applications that offer a consistent experience across all supported browsers and platforms by using ASP.NET and AJAX. In 2006, Microsoft began developing a solution to extend into the browser and offer media experiences more robust than competing plug-in solutions.
In 2007, Microsoft introduced Silverlight. (see footnote) Silverlight is a free plug-in that encompasses a subset of functionality from the .NET Framework and WPF. In a manner similar to the JVM (see footnote), Silverlight runs in the browser as a "sandbox" - a secure zone installed into the browser that accommodates Silverlight functionality while completely protecting the host platform from any possibly adverse actions performed by Silverlight.
Silverlight Architecture
Unlike ASP.NET, the bulk of Silverlight processing occurs on the client machine thus decreasing server resource utilization and improving the Web experience on the client. The figure below shows the difference between ASP.NET processing and Silverlight processing:

When a client initially attempts to run a Silverlight application, if the Silverlight plug-in has not been installed on the client machine, it will be downloaded and installed. Upon subsequent requests to run the application, the application will instantiate on the client machine and make requests for resources from the server only when necessary. The Silverlight plug-in can be thought of as a scaled-down version of the full .NET Framework. It only contains those classes and functionality that are applicable to a Silverlight Web client and those were streamlined and optimized for use on the Web client machine.
Silverlight was designed using the same design paradigm as ASP.NET. Each page of a Silverlight application includes an associated code behind file that includes the code that handles events fired by the page. Silverlight resembles WPF in that it uses Extensible Application Markup Language (XAML) to construct the user interface (presentation layer). As Silverlight applications are composed of text-based files that include markup and code, they can be created using any text editor; however, more advanced tools and development environments such as Visual Studio or Expression Blend simplify the task significantly.
Silverlight Technologies
Version 1.0 of Silverlight used JavaScript and supported the industry-leading Windows Media Services enabling delivery of audio and video that includes 2D and vector graphics.
Version 2 includes all features of version 1.0 and:
  • support for the .NET Framework.
  • support for .NET-compliant programming languages such as C#, Visual Basic, Python, and Ruby.
  • support for database operations and language-integrated query (LINQ).
The figure below illustrates the major differences between version 1.0 and version 2:

The diagram located at ClassFiles/WhatIsSilverlight/Demos/SilverlightTechnologyMap.gif gives a broad picture of the technologies to be supported by Silverlight version 2.
Silverlight Hosting
Microsoft Silverlight functionality is completely encapsulated within the Silverlight plug-in. Web applications typically require the server hosting the Web application to meet minimum requirements. Silverlight applications simply require a Web server to be equipped as they would be for hosting HTML documents. Silverlight applications can be hosted on any Web server accessible to the target audience. The two most commonly used Web servers are Microsoft Internet Information Server (IIS) and Apache.
Executing a Silverlight application on a Web client machine is a two-step process. First, the application will detect if the Silverlight plug-in is installed on the Web client machine. If the plug-in is not installed, the user will be prompted with an option to download the plug-in. If the user opts to do so, a request will be made of the Web server to download and install the plug-in. The Silverlight plug-in is embodied in a .dll executable file that is loaded into the Web client browser memory once installed. The only interaction required by the Web client when installing the Silverlight plug-in is to grant permission for the plug-in to be installed. Various Web servers, including Microsoft Internet Information Server (IIS), may require slight configuration modifications so that the Silverlight executable file will be downloaded to the Web client when requested.
Second, once the Silverlight plug-in is installed on the Web client machine, the Silverlight application itself must be downloaded. A Silverlight application may consist of many types of files. Slight configuration modifications may be necessary on the Web server, such as MIME types, so that XAML and XAP files are associated with Silverlight and downloaded correctly to the Web client machine when requested.
Once the Silverlight plug-in is installed on a Web client machine and a Silverlight application is downloaded, the Silverlight application is then hosted on the Web client machine. There are some requirements necessary for the Web client machine as discussed in the sections below, however all media players, audio and video codecs, compilers and the runtime are encapsulated in the Silverlight plug-in.
Linux
Many developers are unaware that a version of the .NET Framework exists for the Linux operating system. Linux is an open source operating system that is supported heavily in the online community. The version of the .NET Framework that supports Linux is named the Mono project and was also developed by the open source community. The developers of the Mono project keep the project close to in sync with the .NET Framework when updates are released by Microsoft and created an initial, limited version of Silverlight (called "Moonlight") that supports Linux in approximately 21 days! (see footnote) You can get up to date information on this project at http://www.mono-project.com/Moonlight.
Future Platforms
The Silverlight plug-in renders graphics and multimedia using a vector-based graphics engine. Vector graphics can easily be scaled from very small displays to very large displays of varying resolutions with virtually no loss of image quality. Silverlight on a Windows Mobile device will accommodate delivering live, streaming, high quality video to smart phones and similar devices. The goal is to enable developers to deliver rich interactive applications (RIA) to any type of device.
Microsoft has announced support for Silverlight on mobile devices with a limited initial support for Windows Mobile and the Nokia S60 models. You can learn more about this future support athttp://www.microsoft.com/silverlight/overview/mobile.aspx.

Silverlight vs. Flash
The most successful browser plug-in is Adobe Flash, which is installed on more than 90 percent of the world’s web browsers. Flash has a long history that spans more than ten years, beginning as a straightforward tool for adding animated graphics and gradually evolving into a platform for developing interactive content. It’s perfectly reasonable for .NET developers to create websites that use Flash content. However, doing so requires a separate design tool and a completely different programming language (ActionScript) and programming environment (Flex). Furthermore, there’s no straightforward way to integrate Flash content with server-side .NET code. For example, creating Flash applications that call .NET components is awkward at best. Using server-side .NET code to render Flash content (for example, a custom ASP.NET control that spits out a Flash content region) is far more difficult.
Silverlight aims to give .NET developers a better option for creating rich web content. Silverlight provides a browser plug-in, with many similar features to Flash, but it’s one that’s designed from the ground up for .NET. Silverlight natively supports the C# language and embraces a range of .NET concepts. As a result, developers can write client-side code for Silverlight in the same language they use for server-side code (such as C# and VB), and they can use many of the same abstractions (including streams, controls, collections, generics, and LINQ). The Silverlight plug-in has an impressive list of features, some of which are shared in common with Flash and a few of which are entirely new and even revolutionary. Here are some highlights:

2D drawing: Silverlight provides a rich model for 2D drawing. Best of all, the content you draw is defined as shapes and paths, so you can manipulate this content on the client side. You can even respond to events (like a mouse click on a portion of a graphic), which makes it easy to add interactivity to anything you draw.

Controls: Developers don’t want to reinvent the wheel, so Silverlight is stocked with a few essentials, including buttons, text boxes, lists, and even a DataGrid. Best of all, these basic building blocks can be restyled with custom visuals if you want all of the functionality but none of the stock look.

Animation: Silverlight has a time-based animation model that lets you define what should happen and how long it should take. The Silverlight plug-in handles the sticky details, such as interpolating intermediary values and calculating the frame rate.

Media: Silverlight provides playback of a range of video standards, including highdefinition H.264 video and AAC audio. Silverlight doesn’t use the Windows Media Player ActiveX control or browser plug-in—instead, you can create any front end you want, and you can even show video in full-screen mode.

The Common Language Runtime: Most impressively, Silverlight includes a scaled-down version of the CLR, complete with an essential set of core classes, a garbage collector, a just-in-time (JIT) compiler, support for generics, threading, and so on. In many cases, developers can take code written for the full .NET CLR and use it in a Silverlight
application with only moderate changes.

Networking: Silverlight applications can call old-style ASP.NET web services (.asmx) or Windows Communication Foundation (WCF) web services. They can also send manually created XML requests over HTTP and even open direct socket connections for fast two-way communication. This gives developers a great way to combine rich clientside code with secure server-side routines.

Data binding: Although it’s not as capable as in its big brother (WPF), Silverlight data binding provides a convenient way to display large amounts of data with minimal code. You can pull your data from XML or in-memory objects, giving you the ability to call a web service, receive a collection of objects, and display their data in a web page—often
with just a couple of lines of code.

Multithreading: A Silverlight application can take advantage of the multithreading capability of modern operating systems. You can easily run background code to perform time-consuming tasks (such as contacting a web service or refreshing a calculation).

Visual Studio vs. Expression Blend
If you’re still trying to understand how Visual Studio and Expression Blend stack up, here’s a quick overview:

Visual Studio 2010: It has everything you need to develop Silverlight applications, with a visual designer for Silverlight pages. Using this designer, you can drag, drop, and draw your user interface into existence (which isn’t always the best idea), and you can get a live preview of what it looks like (which is terrifically useful).

Expression Blend 4: It provides the rich support for creating Silverlight user interface, with visual tools that surpass Visual Studio. For certain types of user interface grunt work (for example, creating a nice gradient fill), it’s a remendous help. Expression Blend also supports a fun application prototyping tool called SketchFlow and includes a decent coding editor that’s designed to look like Visual Studio. However, it lacks many advanced and important development tools, such as debugging, code refactoring, and project source control.

Understanding Silverlight Websites
You can create two types of Silverlight websites in Visual Studio or Expression Blend:

• An ordinary website with HTML pages: In this case, the entry point to your Silverlight application is a basic HTML file that includes a Silverlight content region.

• ASP.NET website: In this case, Visual Studio creates two projects—one to contain the Silverlight application files and one to hold the server-side ASP.NET website that will be deployed alongside your Silverlight files. The entry point to your Silverlight application can be an ordinary HTML file, or it can be an ASP.NET web page that includes server generated content. So, which approach is best? No matter which option you choose, your Silverlight application will run the same way—the client browser will receive an HTML document, which will include a Silverlight content region, and the Silverlight code will run on the local computer, not the web server. However, the ASP.NET web approach makes it easier to mix ASP.NET and Silverlight content. This is usually a better approach in the following cases:

• You want to create a website that contains both ASP.NET web pages and Silverlightenhanced
pages.

• You want to create a Silverlight application that calls a web service, and you want to design the web service at the same time (and deploy it to the same web server).

• You want to generate Silverlight content indirectly, using specialized ASP.NET web controls.

Creating a Stand-Alone Silverlight Project
The easiest way to start using Silverlight is to create an ordinary website with HTML pages and no server-side code. Here’s how:

1. Select File New Project in Visual Studio, choose the Visual C# Silverlight group of project types, and then select the Silverlight Application template. As usual, you need to pick a project name and a location on your hard drive before clicking OK to create the project.

2. At this point, Visual Studio will prompt you to choose whether you want to create a fullfledged ASP.NET website that can run server-side code along with your Silverlight project (see Figure 1-1). Uncheck the “Host the Silverlight application in a new Web site” option to keep things simple.

3. Underneath, choose the version of Silverlight application that you want to create. If you aren’t using any of the new features in Silverlight 4, you’ll get slightly more reach with Silverlight 3 (which, at the time of this writing, is still installed on more computers). If you haven’t installed the Silverlight 4 Tools for Visual Studio 2010, you won’t get an option for creating Silverlight 4 applications.



Every Silverlight project starts with a small set of essential files, as shown in Figure 1-2. All the files that end with the extension .xaml use a flexible markup standard called XAML, which you’ll dissect in the next chapter. All the files that end with the extension .cs hold the C# source code that powers your application.



Creating a Simple Silverlight Page
As you’ve already learned, every Silverlight page includes a markup portion that defines the visual appearance (the XAML file) and a source code file that contains event handlers. To customize your first Silverlight application, you simply need to open the MainPage.xaml file and begin adding markup. Visual Studio gives you two ways to look at every XAML file—as a visual preview (known as the design surface) or the underlying markup (known as the XAML view). By default, Visual Studio shows both parts, stacked one on the other. Figure 1-4 shows this view and points out the buttons you can use to change your vantage point.



To get started, you can try creating the page shown in the following example, which defines a block of text and a button. The portions in bold have been added to the basic page template that Visual Studio generated when you created the project.

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="400">
Margin="5">





This creates a page that has a stacked arrangement of two elements. On the top is a block of
text with a simple message. Underneath it is a button.

Adding Event-Handling Code
You attach event handlers to the elements in your page using attributes, which is the same approach that developers take in WPF, ASP.NET, and JavaScript. For example, the Button element exposes an event named Click that fires when the button is triggered with the mouse or keyboard. To react to this event, you add the Click attribute to the Button element and set it to the name of a method in your code:

Content="Click Me!"
Margin="5">


This example assumes that you’ve created an event-handling method named cmdClickMe_Click. Here’s what it looks like in the MainPage.xaml.cs file:

private void cmdClickMe_Click(object sender, RoutedEventArgs e)
{
lblMessage.Text = "Goodbye, cruel world.";
}

Creating an ASP.NET-Hosted Silverlight Project
Although Silverlight does perfectly well on its own, you can also develop, test, and deploy it as part of an ASP.NET website. Here’s how to create a Silverlight project and an ASP.NET website that uses it in the same solution:

1. Select File New Project in Visual Studio, choose the Visual C# Silverlight group of project types, and then select the Silverlight Application template. It’s a good idea to use the “Create directory for solution” option so you can group together the two projects that Visual Studio will create—one for the Silverlight assembly and one for
ASP.NET website.

2. Ordinarily, Visual Studio assumes you want to use the latest and greatest version of .NET for the server-side portion of any web applications you create. If this isn’t what you want, you can pick a different version of .NET from the drop-down list at the top of the New Project window. For example, if you pick .NET Framework 3.5, your ASP.NET website will be configured to use this slightly older version of .NET.

3. Once you’ve picked the solution name and project name, click OK to create it.

4. Make sure the option “Host the Silverlight application in a new website” is checked.

5. Supply a project name for the ASP.NET website. By default, it’s your project name with the added text .Web at the end, as shown in Figure 1-7.

6. In the drop-down list underneath, choose the way you want Visual Studio to manage your project—either as a web project or as a website. The choice has no effect on how Silverlight works. If you choose Web Project, Visual Studio uses a project file to track the contents of your web application and compiles your web page code into a single
assembly before you run it. If you choose Web Site, Visual Studio simply assumes everything in the application folder is part of your web application. Your web page code will be compiled the first time a user requests a page (or when you use the precompilation tool aspnet_compiler.exe). For more information about the difference between web projects and projectless websites, as well as other ASP.NET basics, refer to Pro ASP.NET 4 in C# 2010.

7. Choose whether you want to create a Silverlight 3 or Silverlight 4 application in the Silverlight Version list.

8. You can also choose to enable WCF RIA services, which are a set of web services that help you bridge the gap between the client-side world of Silverlight and the server-side world of ASP.NET. For a basic Silverlight website, leave this option unchecked.

9. Finally, click OK to create the solution.



There are two ways to integrate Silverlight content into an ASP.NET application:
• Create HTML files with Silverlight content: You place these files in your ASP.NET website folder, just as you would with any other ordinary HTML file. The only limitation of this approach is that your HTML file obviously can’t include ASP.NET controls, because it won’t be processed on the server.

• Place Silverlight content inside an ASP.NET web form: In this case, the element that loads the Silverlight plug-in is inserted into a dynamic .aspx page. You can add other ASP.NET controls to different regions of this page. The only disadvantage to this approach is that the page is always processed on the server. If you aren’t actually using any server-side ASP.NET content, this creates an extra bit of overhead that you don’t need when the page is first requested.

Of course, you’re also free to mingle both of these approaches and use Silverlight content in dedicated HTML pages and inside ASP.NET web pages in the same site. When you create a Silverlight project with an ASP.NET website in Visual Studio, you’ll start with both. For example,
if your Silverlight project is named SilverlightApplication1, you can use SilverlightApplication1TestPage.html or SilverlightApplication1TestPage.aspx.

Figure 1-8 shows how a Silverlight and ASP.NET solution starts. Along with the two test pages, the ASP.NET website also includes a Default.aspx page (which can be used as the entry point to your ASP.NET website), a web.config file (which allows you to configure various website settings), and a Silverlight.js file (which has JavaScript helper functions for creating and initializing the Silverlight content region).



The Silverlight and ASP.NET option provides essentially the same debugging experience as a Silverlight-only olution. When you run the solution, Visual Studio compiles both projects and copies the Silverlight assembly to the ClientBin folder in the ASP.NET website. (This is similar to assembly references—if an ASP.NET website references a private DLL, Visual Studio automatically copies this DLL to the Bin folder.)

Once both projects are compiled, Visual Studio looks to the startup project (which is the ASP.NET website) and looks for the currently selected page. It then launches the default browser and navigates to that page. The difference is that it doesn’t request the start page directly from the file system. Instead, it communicates with its built-in test web server. This web server automatically loads on a randomly chosen port. It acts like a scaled-down version of IIS but accepts requests only from the local computer. This gives you the ease of debugging without needing to configure IIS virtual directories. Figure 1-9 shows the same Silverlight application you considered earlier but hosted by ASP.NET.



The HTML Entry Page
The last ingredient in the deployment picture is the HTML test page. This page is the entry point into your Silverlight content—in other words, the page the user requests in the web browser. In a stand-alone Silverlight project, Visual Studio names this file TestPage.html. In an ASP.NET-hosted Silverlight project, Visual Studio names it to match your project name. Either way, you’ll probably want to rename it to something more appropriate.

The HTML test page doesn’t actually contain Silverlight markup or code. Instead, it simply sets up the content region for the Silverlight plug-in, using a small amount of JavaScript. (For this reason, browsers that have JavaScript disabled won’t be able to see Silverlight content.)

Here’s a slightly shortened version of the HTML test page that preserves the key details:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SilverlightApplication1</title>
<style type="text/css">
...
</style>
<script type="text/javascript">
...
</script>
</head>
<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2,"
type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="SilverlightApplication1.xap" />
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="4.0.50401.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0"
style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181"
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>

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 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.

XAML Basics
The XAML standard is quite straightforward once you understand a few ground rules:

• Every element in a XAML document maps to an instance of a Silverlight class. The name of the element matches the name of the class exactly. For example, the element

• As with any XML document, you can nest one element inside another. As you’ll see, XAML gives every class the flexibility to decide how it handles this situation. However, nesting is usually a way to express containment—in other words, if you find a Button element inside a Grid element, your user interface probably includes a Grid that
contains a Button inside.

• You can set the properties of each class through attributes. However, in some situations, an attribute isn’t powerful enough to handle the job. In these cases, you’ll use nested tags with a special syntax.

Before continuing, take a look at this bare-bones XAML document, which represents a blank page (as created by Visual Studio). The lines have been numbered for easy reference:

1 <UserControl x:Class="SilverlightApplication1.MainPage"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
7
8 <Grid x:Name="LayoutRoot">
9 </Grid>
10 </UserControl>

Core Silverlight Namespaces
The first two namespaces are the most important. You’ll need them to access essential parts of the Silverlight runtime:

• http://schemas.microsoft.com/winfx/2006/xaml/presentation is the core Silverlight namespace. It encompasses all the essential Silverlight classes, including the UserControl and Grid. Ordinarily, this namespace is declared without a namespace
prefix, so it becomes the default namespace for the entire document. In other words, every element is automatically placed in this namespace unless you specify otherwise.

• http://schemas.microsoft.com/winfx/2006/xaml is the XAML namespace. It includes various XAML utility features that allow you to influence how your document is interpreted. This namespace is mapped to the prefix x. That means you can apply it by placing the namespace prefix before the name of an XML element or attribute (as in and x:Class="ClassName").

Properties and Events in XAML
So far, you’ve considered a relatively unexciting example—a blank page that hosts an empty Grid control. Before going any further, it’s worth introducing a more realistic page that includes several elements. Figure 2-1 shows an example with an automatic question answerer.



The eight ball page includes four elements: a Grid (the most common tool for arranging layout in Silverlight), two TextBox objects, and a Button. The markup that’s required to arrange and configure these elements is significantly longer than the previous examples. Here’s an abbreviated listing that replaces some of the details with an ellipsis  (. . .) to expose the overall structure:

<UserControl x:Class="EightBall.MainPage"
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="grid1">
<Grid.Background>
...
</Grid.Background>
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<TextBox x:Name="txtQuestion" ... >
</TextBox>
<Button x:Name="cmdAnswer" ... >
</Button>
<TextBox x:Name="txtAnswer" ... >
</TextBox>
</Grid>
</UserControl>

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 propertyelement 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>
The key detail that makes this work is the period (.) in the element name. This distinguishes properties from other types of nested content. This still leaves one detail—namely, once you’ve identified the complex property you want to configure, how do you set it? Here’s the trick. Inside the nested element, you can add another tag to instantiate a specific class. In the eight ball example (shown in Figure 2-1), the background is filled with a gradient. To define the gradient you want, you need to create a LinearGradientBrush object. Using the rules of XAML, you can create the LinearGradientBrush object using an element with the name LinearGradientBrush:

<Grid x:Name="grid1">
<Grid.Background>
<LinearGradientBrush>
</LinearGradientBrush>
</Grid.Background>
...
</Grid>
The LinearGradientBrush is part of the Silverlight set of namespaces, so you can keep using the default XML namespace for your tags. However, it’s not enough to simply create the LinearGradientBrush—you also need to specify the colors in that gradient. You do this by filling the LinearGradientBrush.GradientStops property with a collection of GradientStop objects. Once again, the GradientStops property is too complex to be set with an attribute value alone. Instead, you need to rely on the propertyelement syntax:

<Grid x:Name="grid1">
<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>

Any set of XAML tags can be replaced with a set of code statements that performs the same task. The tags shown previously, which fill the background with a gradient of your choice, are equivalent to the following code:

LinearGradientBrush brush = new LinearGradientBrush();
GradientStop gradientStop1 = new GradientStop();
gradientStop1.Offset = 0;
gradientStop1.Color = Colors.Yellow;
brush.GradientStops.Add(gradientStop1);
GradientStop gradientStop2 = new GradientStop();
gradientStop2.Offset = 0.5;
gradientStop2.Color = Colors.White;
brush.GradientStops.Add(gradientStop2);
GradientStop gradientStop3 = new GradientStop();
gradientStop3.Offset = 1;
gradientStop3.Color = Colors.Purple;
brush.GradientStops.Add(gradientStop3);
grid1.Background = brush;

Element-to-Element Binding
In the previous section, you saw how to use the StaticResource markup extension, which gives XAML additional capabilities (in this case, the ability to easily refer to a resource that’s defined elsewhere in your markup). You’ll see the StaticResource at work throughout the examples in this book. Another markup extension that gets heavy use is the Binding expression, which sets up a relationship that funnels information from a source object to a target control.
In Chapter 16, you’ll use binding expressions to create data-bound pages that allow the user to review and edit the information in a linked data object. But in this chapter, you’ll take a quick look at a more basic skill—the ability to connect two elements together with a binding expression.




One-Way Binding
To understand how you can bind an element to another element, consider the simple window shown in Figure. It contains two controls: a Slider and a TextBlock with a single line of text. If you pull the thumb in the slider to the right, the font size of the text is increased immediately. If you pull it to the left, the font size is reduced.



Clearly, it wouldn’t be difficult to create this behavior using code. You would simply react to the Slider.ValueChanged event and copy the current value from the slider to the TextBlock. However, data binding makes it even easier.
When using data binding, you don’t need to make any change to your source object (which is the Slider in this example). Just configure it to take the right range of values, as you would ordinarily.

<Slider x:Name="sliderFontSize" Margin="3"
Minimum="1" Maximum="40" Value="10">
</Slider>
The binding is defined in the TextBlock element. Instead of setting the FontSize using a literal value, you use a binding expression, as shown here:

<TextBlock Margin="10" Text="Simple Text" x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}" >
</TextBlock>

Two-Way Binding
Interestingly, there’s a way to force values to flow in both directions: from the source to the target and from the target to the source. The trick is to set the Mode property of the Binding. Here’s a revised bidirectional binding that allows you to apply changes to either the source or the target and have the other piece of the equation update itself automatically:

<TextBlock Margin="10" Text="Simple Text" Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value, Mode=TwoWay}" >
</TextBlock>

In this example, there’s no reason to use a two-way binding, because you can solve the problem by manipulating the value of the slider rather than changing the font size of the TextBlock. However, consider a variation of this example that includes a text box where the user can set the font size precisely (see Figure)



Here, the text box needs to use a two-way binding, because it both receives the bound data value and sets it. When the user drags the slider (or clicks a button), the text box receives the new slider value. And when the user types a new value in the text box, the binding copies the value to the slider.

Here’s the two-way binding expression you need:
<TextBox Text="{Binding ElementName=lblSampleText, Path=FontSize, Mode=TwoWay}">
</TextBox>

The Layout Containers
A Silverlight window can hold only a single element. To fit in more than one element and create a more practical user interface, you need to place a container in your page and then add other elements to that container. Your layout is determined by the container that you use. All the Silverlight layout containers are panels that derive from the abstract System.Windows.Controls.Panel class.

Simple Layout with the StackPanel
The StackPanel is one of the simplest layout containers. It simply stacks its children in a single row or column. These elements are arranged based on their order. For example, consider this page, which contains a stack with one TextBlock and four buttons:

<UserControl x:Class="Layout.SimpleStack"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="White">
<TextBlock Text="A Button Stack"></TextBlock>
<Button Content="Button 1"></Button>
<Button Content="Button 2"></Button>
<Button Content="Button 3"></Button>
<Button Content="Button 4"></Button>
</StackPanel>
</UserControl>



The StackPanel can also be used to arrange elements horizontally by setting the Orientation property:
<StackPanel Orientation="Horizontal" Background="White">



Margins
There’s an obvious problem with the StackPanel example in its current form. A well-designed page doesn’t just contain elements—it also includes a bit of extra space in between the elements. To introduce this extra space and make the StackPanel example less cramped, you can set control margins.

When setting margins, you can set a single width for all sides, like this:
<Button Margin="5" Content="Button 3"></Button>

Alternatively, you can set different margins for each side of a control in the order left, top,
right, bottom:
<Button Margin="5,10,5,10" Content="Button 3"></Button>

In code, you can set margins using the Thickness structure:
cmd.Margin = new Thickness(5);

The WrapPanel and DockPanel
Obviously, the StackPanel alone can’t help you create a realistic user interface. To complete the picture, the StackPanel needs to work with other more capable layout containers. Only then can you assemble a complete window. The most sophisticated layout container is the Grid, which you’ll consider later in this chapter. But first, it’s worth looking at the WrapPanel and DockPanel, which are two simple layout containers that are available as part of the Silverlight Toolkit. Both complement the StackPanel by offering different layout behavior.

To use the WrapPanel or the DockPanel, you need to add a reference to the System.Windows.Controls.Toolkit.dll assembly where they are defined. To get this assembly, you must install the Silverlight Toolkit, which is available at http://silverlight.codeplex.com.

Once you’ve added the assembly reference, you need to map the namespace so it’s available in your markup, as shown here:

<UserControl x:Class="Layout.WrapAndDock" ...
xmlns:toolkit=
"clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit">

You can now define the WrapPanel and DockPanel using the namespace prefix toolkit:

<toolkit:WrapPanel ...></toolkit:WrapPanel>
You can skip a few steps by adding the WrapPanel from the Toolbox. Visual Studio will then
add the appropriate assembly reference, map the namespace, and insert the XML markup for
the control.

The WrapPanel
The WrapPanel lays out controls in the available space, one line or column at a time. By default, the WrapPanel.Orientation property is set to Horizontal; controls are arranged from left to right and then on subsequent rows. However, you can use Vertical to place elements in multiple columns.

Here’s an example that defines a series of buttons with different alignments and places them into the WrapPanel:
<toolkit:WrapPanel Margin="3">
<Button VerticalAlignment="Top" Content="Top Button"></Button>
<Button MinHeight="60" Content="Tall Button"></Button>
<Button VerticalAlignment="Bottom" Content="Bottom Button"></Button>
<Button Content="Stretch Button"></Button>
<Button VerticalAlignment="Center" Content="Centered Button"></Button>
</toolkit:WrapPanel>





The DockPanel
The Silverlight Toolkit also includes a layout container called the DockPanel. It stretches controls against one of its outside edges. The easiest way to visualize this is to think of the toolbars that sit at the top of many Windows applications. These toolbars are docked to the top of the window. As with the StackPanel, docked elements get to choose one aspect of their layout. For example, if you dock a button to the top of a DockPanel, it’s stretched across the entire width of the DockPanel but given whatever height it requires (based on the content and the MinHeight property). On the other hand, if you dock a button to the left side of a container, its height is stretched to fit the container, but its width is free to grow as needed. The obvious question is this: How do child elements choose the side where they want to dock? The answer is through an attached property named Dock, which can be set to Left, Right, Top, or Bottom. Every element that’s placed inside a DockPanel automatically acquires this property.

Here’s an example that puts one button on every side of a DockPanel:
<toolkit:DockPanel LastChildFill="True">
<Button toolkit:DockPanel.Dock="Top" Content="Top Button"></Button>
<Button toolkit:DockPanel.Dock="Bottom" Content="Bottom Button"></Button>
<Button toolkit:DockPanel.Dock="Left" Content="Left Button"></Button>
<Button toolkit:DockPanel.Dock="Right" Content="Right Button"></Button>
<Button Content="Remaining Space"></Button>
</toolkit:DockPanel>



The Two-Step Layout Process
Every panel uses the same plumbing: a two-step process that’s responsible for sizing and arranging children. The first stage is the measure pass, and it’s at this point that the panel determines how large its children want to be. The second stage is the layout pass, and it’s at this point that each control is assigned its bounds. Two steps are required, because the panel might need to take into account the desires of all its children before it decides how to partition the
available space.

You add the logic for these two steps by overriding the oddly named MeasureOverride() and ArrangeOverride() methods, which are defined in the FrameworkElement class as part of the Silverlight layout system. The odd names represent that the MeasureOverride() and ArrangeOverride() methods replace the logic that’s defined in the MeasureCore() and ArrangeCore() methods that are defined in the UIElement class. These methods are not overridable.

MeasureOverride()
The first step is to determine how much space each child wants using the MeasureOverride() method. However, even in the MeasureOverride() method, children aren’t given unlimited room. At a bare minimum, children are confined to fit in the space that’s available to the panel. Optionally, you might want to limit them more stringently. For example, a Grid with two proportionally sized rows will give children half the available height. A StackPanel will offer the first element all the space that’s available and then offer the second element whatever’s left, and so on.
Every MeasureOverride() implementation is responsible for looping through the collection of children and calling the Measure() method of each one. When you call the Measure() method, you supply the bounding box—a Size object that determines the maximum available space for the child control. At the end of the MeasureOverride() method, the panel returns the space it needs to display all its children and their desired sizes. Here’s the basic structure of the MeasureOverride() method, without the specific sizing details:

protected override Size MeasureOverride(Size panelSpace)
{
// Examine all the children.
foreach (UIElement element in this.Children)
{
// Ask each child how much space it would like, given the
// availableElementSize constraint.
Size availableElementSize = new Size(...);
element.Measure(availableElementSize);
// (You can now read element.DesiredSize to get the requested size.)
}
// Indicate how much space this panel requires.
// This will be used to set the DesiredSize property of the panel.
return new Size(...);
}
The Measure() method doesn’t return a value. After you call Measure() on a child, that child’s DesiredSize property provides the requested size. You can use this information in your calculations for future children (and to determine the total space required for the panel). You must call Measure() on each child, even if you don’t want to constrain the child’s size or use the DesiredSize property. Many elements will not render themselves until you’ve called Measure(). If you want to give a child free rein to take all the space it wants, pass a Size object with a value of Double.PositiveInfinity for both dimensions. (The ScrollViewer is one element that uses this strategy, because it can handle any amount of content.) The child will then return the space it needs for all its content. Otherwise, the child will normally return the space it needs for its content or the space that’s available—whichever is smaller. At the end of the measuring process, the layout container must return its desired size. In a
simple panel, you might calculate the panel’s desired size by combining the desired size of every child.

ArrangeOverride()
Once every element has been measured, it’s time to lay them out in the space that’s available. The layout system calls the ArrangeOverride() method of your panel, and the panel calls the Arrange() method of each child to tell it how much space it’s been allotted. (As you can probably guess, the Arrange() method triggers the ArrangeOverride() method, much as the Measure() method triggers the MeasureOverride() method.) When measuring items with the Measure() method, you pass in a Size object that defines the bounds of the available space. When placing an item with the Arrange() method, you pass in a System.Windows.Rect object that defines the size and position of the item. At this point, it’s as though every element is placed with Canvas-style X and Y coordinates that determine the distance between the top-left corner of your layout container and the element.

Here’s the basic structure of the ArrangeOverride() method, without the specific sizing details:
protected override Size ArrangeOverride(Size panelSize)
{
// Examine all the children.
foreach (UIElement element in this.Children)
{
// Assign the child its bounds.
Rect elementBounds = new Rect(...);
element.Arrange(elementBounds);
// (You can now read element.ActualHeight and element.ActualWidth
// to find out the size it used.)
}

// Indicate how much space this panel occupies.
// This will be used to set the ActualHeight and ActualWidth properties
// of the panel.
return arrangeSize;
}

The Application Model

The Application Class
You took your first look at the App.xaml file. Much as every XAML page is a template for a custom class that derives from System.Windows.UserControl, the App.xaml file is a template for a custom class (named App by default) that derives from System.Windows.Application. You’ll find the class definition in the App.xaml.cs file:

public partial class App : Application
{ ... }

When the Silverlight plug-in loads your application, it begins by creating an instance of the App class. From that point on, the application object serves as your entry point for a variety of application-specific features, including application events, resources, and services.

Accessing the Current Application
You can retrieve a reference to the application object at any time, at any point in your code, using the static Application.Current property.
However, this property is typed as a system.Windows.Application object. To use any custom properties or methods that you’ve added to the derived application class, you must cast the reference to the App type. For example, if you’ve added a method named DoSomething() to the App.xaml.cs file, you can invoke it with code like this:

((App)Application.Current).DoSomething();

This technique allows you to use your custom application class as a sort of switchboard for global tasks that affect your entire application. For example, you can add methods to your application class that control navigation or registration, and you can add properties that store global data. You’ll see the App class used this way in examples throughout this book.

Application Events

You took your first look at the life cycle of a Silverlight application. Here’s a quick review:
1. The user requests the HTML entry page in the browser.
2. The browser loads the Silverlight plug-in. It then downloads the XAP file that contains your application.
3. The Silverlight plug-in reads the AppManifest.xml file from the XAP to find out what assemblies your application uses. It creates the Silverlight runtime environment and then loads your application assembly (along with any dependent assemblies).
4. The Silverlight plug-in creates an instance of your custom application class (which is defined in the App.xaml and App.xaml.cs files).
5. The default constructor of the application class raises the Startup event.
6. Your application handles the Startup event and creates the root visual object for your application.

From this point on, your page code takes over, until it encounters an unhandled error (UnhandledException) or finally ends (Exit). These events—Startup, UnhandledException, and Exit—are the core events that the Application class provides. Along with these standards, the Application class includes two events—InstallStateChanged and CheckAndDownloadUpdateCompleted—that are designed for use with the out-of-browser applications. If you look at the contents of the App.xaml.cs file, you’ll see that in Visual Studio, the
application constructor contains some pregenerated code. This code attaches an event handler
to the three application events:

public App()
{
this.Startup += this.Application_Startup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
InitializeComponent();
}

As with the page and element events you’ve considered in earlier chapters, there are two ways to attach application event handlers. Instead of using code, you can add event attributes to the XAML markup, as shown here:

<Application ... x:Class="SilverlightApplication1.App"
Startup="Application_Startup" >

There’s no reason to prefer one approach to the other. By default, Visual Studio uses the code approach shown first. In the following sections, you’ll see how you can write code that plugs into the
application events.

Application Startup

By default, the Application_Startup method creates the first page and assigns it to the Application.RootVisual property, ensuring that it becomes the top-level application element— the visual core of your application:

private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new MainPage();
}
Although you can change the root visual by adding or removing elements, you can’t reassign the RootVisual property at a later time. After the application starts, this property is essentially read-only.

Initialization Parameters
The Startup event passes in a StartupEventArgs object, which includes one additional detail: initialization parameters. This mechanism allows the page that hosts the Silverlight control to pass in custom information. This is particularly useful if you host the same Silverlight application on different pages or you want the Silverlight application to vary based on userspecific or session-specific information. For example, you can customize the application’s view depending on whether users are entering from the customer page or the employee page. Or, you may choose to load different information based on the product the user is currently viewing. Just remember that the initialization parameters come from the tags of the HTML entry page, and a malicious user can alter them.

For example, imagine you want to pass a ViewMode parameter that has two possible values, Customer or Employee, as represented by this enumeration:

public enum ViewMode
{
Customer, Employee
}
You need to change a variety of details based on this information, so it makes sense to store it somewhere that’s accessible throughout your application. The logical choice is to add a property to your custom application class, like this:

private ViewMode viewMode = ViewMode.Customer;
public ViewMode ViewMode
{
get { return viewMode; }
}

This property defaults to customer view, so it needs to be changed only if the web page specifically requests the employee view. To pass the parameter into your Silverlight application, you need to add a element to the markup in the Silverlight content region. This parameter must have the name initParams. Its value is a comma-separated list of name-value pairs that set your custom parameters. For example, to add a parameter named viewMode, you add the following line (shown in bold) to your markup:

<div id="silverlightControlHost">
<object data="data:application/x-silverlight,"
type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="TransparentSilverlight.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="initParams" value="viewMode=Customer" />
...
</object>
<iframe style="visibility:hidden;height:0;width:0;border:0px"></iframe>
</div>

Then, you can retrieve this from the StartupEventArgs.InitParams collection. However, you must check first that it exists:

private void Application_Startup(object sender, StartupEventArgs e)
{
// Take the view mode setting, and store in an application property.
if (e.InitParams.ContainsKey("viewMode"))
{
string view = e.InitParams["viewMode"];
if (view == "Employee") this.viewMode = ViewMode.Employee;
}
// Create the root page.
this.RootVisual = new Page();
}

If you have many possible values, you can use the following leaner code to convert the string to the corresponding enumeration value, assuming the text matches exactly:

string view = e.InitParams["viewMode"];
try
{
this.viewMode = (ViewMode)Enum.Parse(typeof(ViewMode), view, true);
}
catch { }

Now, different pages are free to pass in a different parameter and launch your application with different view settings. Because the view information is stored as a property in the custom application class (named App), you can retrieve it anywhere in your application:

lblViewMode.Text = "Current view mode: " +
((App)Application.Current).ViewMode.ToString();

Figure shows what you’ll see when you run the test page that uses the Customer
view mode.



Unhandled Exceptions
Although you should use disciplined exception-handling code in situations where errors are possible (for example, when reading a file, downloading web content, or accessing a web service), it’s not always possible to anticipate all sources of error. If your application encounters an error that isn’t handled, it will end, and the Silverlight content region will revert to a blank space. If you’ve included JavaScript code that reacts to potential errors from the Silverlight plug-in, that code will run. Otherwise, you won’t receive any indication about the error that’s just occurred. The Application.UnhandledException event gives you a last-ditch chance to respond to an exception before it reaches the Silverlight plug-in and terminates your application. This code is notably different from the JavaScript error-handling code that you may add to the page, because it has the ability to mark an exception as handled. Doing so effectively neutralizes the exception, preventing it from rising to the plug-in and ending your application.

Here’s an example that checks the exception type and decides whether to allow the application to continue:
public void Application_UnhandledException(object sender,
ApplicationUnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is FileNotFoundException)
{
// Suppress the exception and allow the application to continue.
e.Handled = true;
}
}

Ideally, an exception like this should be handled closer to where it occurs—for example, in your page code, when you’re performing a task that may result in a FileNotFoundException. Application-level error handling isn’t ideal, because it’s difficult to identify the original process that caused the problem and it’s awkward to notify the user about what went wrong. But application-level error handling does occasionally offer a simpler and more streamlined way to handle certain scenarios—for example, when a particular type of exception crops up in numerous places. After you’ve neutralized the error, it makes sense to notify the user. One option is to call a custom method in your root visual. For example, this code calls a custom ReportError() method in the MainPage class, which is the root visual for this application:

MainPage rootPage = (MainPage)this.RootVisual;
rootPage.ReportError(e.ExceptionObject);

Now the MainPage.ReportError() method can examine the exception object and display the appropriate message in an element on the page. In an effort to make your applications a little more resilient, Visual Studio adds a bit of boilerplate error-handling code to every new Silverlight application. This code checks whether a debugger is currently attached.

public void Application_UnhandledException(object sender,
ApplicationUnhandledExceptionEventArgs e)
{
if (!System.Diagnostics.Debugger.IsAttached)
{
// Suppress the exception and allow the application to continue.
e.Handled = true;
try
{
// Build an error message.
string errorMsg = e.ExceptionObject.Message +
e.ExceptionObject.StackTrace;
errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
// Use the Window.Eval() method to run a line of JavaScript code that
// will raise an error with the error message.
System.Windows.Browser.HtmlPage.Window.Eval(
"throw new Error(\"Unhandled Error in Silverlight 2 Application " +
errorMsg + "\");");
}
catch {}
}
}
Essentially, this code converts a fatal Silverlight error to a relatively harmless JavaScript error. The way the JavaScript error is dealt with depends on the browser. In Internet Explorer, a yellow alert icon appears in the status bar. (Double-click the alert icon to get the full error details, as shown in Figure 6-2.) In Firefox, a script error message appears. Either way, the error won’t stop your application from continuing.



Custom Splash Screens
If a Silverlight application is small, it downloads quickly and appears in the browser. If a Silverlight application is large, it may take a few seconds to download. As long as your application takes longer than 500 milliseconds to download, Silverlight shows an animated splash screen.

The built-in splash screen isn’t too exciting—it displays a ring of blinking circles and the
percentage of the application that’s been downloaded so far (see Figure)



If you don’t like the stock splash screen, you can easily create your own (see Figure). Essentially, a custom splash screen is a XAML file with the graphical content you want to display and a dash of JavaScript code that updates the splash screen as the application is downloaded. You can’t use C# code at this point, because the Silverlight programming environment hasn’t been initialized yet. However, this isn’t a major setback, because the code you need is relatively straightforward. It lives in one or two event-handling functions that are triggered as content is being downloaded and after it’s finished, respectively. And because JavaScript is syntactically similar to C#, you won’t have much trouble putting together the code you need.



Placing Resources in the Application Assembly
This is the standard approach, and it’s similar to the approach used in other types of .NET applications (such as WPF applications). For example, if you want to show an image in Silverlight’s Image element, begin by adding the image file to your project. By default, Visual Studio gives image files the Resource build action, as shown in Figure. (To change the build action of an existing file, select it in the Solution Explorer, and make a new selection in the Build Action box in the Properties pane.)



Now, when you compile your application, the resource will be embedded in the project assembly, and the project assembly will be placed in the XAP file.

Using an embedded resource is easy because of the way Silverlight uses URIs. If you use a relative URI with the Image (for graphics) or MediaElement (for sound and video files), Silverlight checks the assembly for a resource with the right name. That means this is all you need to use the resource shown in Figure:
<Image Source="grandpiano.jpg"></Image>

Using Subfolders
It’s possible to use the folders to group resource files in your project. This changes how the resource is named. For example, consider Figure 6-6, which puts the grandpiano.jpg file in a subfolder named Images.



Now, you need to use this URI:
<Image Source="Images/grandpiano.jpg"></Image>

Programmatically Retrieving a Resource
Using resources is easy when you have an element that supports Silverlight’s URI standard, such as Image or MediaElement. However, in some situations, you need to manipulate your resource in code before handing it off to an element, or you may not want to use an element at all. For example, you may have some static data in a text or binary file that’s stored as a resource. In your code, you want to retrieve this file and process its data.

To perform this task, you need the help of the Application.GetResourceStream() method. It allows you to retrieve the data for a specific resource, which you indicate by supplying the correct URI. The trick is that you need to use the following URI format: AssemblyName;component/ResourceFileName For example, if you have a resource named ProductList.bin in a project named SilverlightApplication1, you use this line of code:

StreamResourceInfo sri = Application.GetResourceStream(new Uri("SilverlightApplication1;component/ProductList.bin", UriKind.Relative));

The GetResourceStream() method doesn’t retrieve a stream. Instead, it gets a System.Windows.Resources.StreamResourceInfo object, which wraps a Stream property (with
the underlying stream) and a ContentType property (with the MIME type). Here’s the code that
creates a BinaryReader object for the stream:

BinaryReader reader = new BinaryReader(sri.Stream);

You can now use the methods of the binary reader to pull each piece of data out of the file. The same approach works with StreamReader (for text-based data) and XmlReader (for XML data). But you have a slightly easier option when XML data is involved, because the XmlReader.Create() method accepts either a stream or a URI string that points to a resource. So, if you have a resource named ProductList.xml, this code works:

StreamResourceInfo sri = Application.GetResourceStream(
new Uri("SilverlightApplication1;component/ProductList.xml", UriKind.Relative));
XmlReader reader = XmlReader.Create(sri.Stream, new XmlReaderSettings());
So does this more streamlined approach:
XmlReader reader = XmlReader.Create("ProductList.xml")

Class Library Assemblies
So far, the examples you’ve seen in this book have placed all their code into a single assembly. For a small or modest-sized Silverlight application, this straightforward design makes good sense. But it’s not hard to imagine that you might want to factor out certain functionality and place it in a separate class library assembly. Usually, you’ll take this step because you want to reuse that functionality with more than one Silverlight application. Alternatively, you may want to break it out it so it can be coded, compiled, debugged, and revised separately, which is particularly important if that code is being created by a different development team. Creating a Silverlight class library is easy. It’s essentially the same process you follow to create and use class library assemblies in ordinary .NET applications. First, create a new project in Visual Studio using the Silverlight Class Library project template. Then, add a reference in your Silverlight application that points to that project or assembly. The dependent assembly will be copied into the XAP package when you build your application.

Using Resources in an Assembly
Class libraries give you a handy way to share resources between applications. You can embed a resource in a class library and then retrieve it in your application. This technique is easy—the only trick is constructing the right URIs. To pull a resource out of a library, you need to use a URI that includes the application in this format:
/ClassLibraryName;component/ResourceFileName

This is the same format you learned about earlier, in the section “Programmatically Retrieving a Resource,” but with one addition: now, the URI begins with a leading slash, which represents the root of the XAP file. This URI points to the dependent assembly in that file and then indicates a resource in that assembly. For example, consider the ResourceClassLibrary assembly in Figure. It includes a resource named happyface.jpg, and that file has a build action of Resource.



Here’s an image file that uses the resource from the class library:
<Image Source="/ResourceClassLibrary;component/happyface.jpg"></Image>

Downloading Assemblies on Demand
In some situations, the code in a class library is used infrequently, or perhaps not at all for certain users. If the class library contains a significant amount of code or (more likely) has large embedded resources such as graphics, including it with your application will increase the size of your XAP file and lengthen download times needlessly. In this case, you may want to create a separate component assembly—one that isn’t downloaded until you need it. This scenario is similar to on-demand resource downloading. You place the separate resource in a separate file outside of the XAP file but on the same website.

Before you use assembly downloading, you need to make sure the dependent assembly isn’t placed in the XAP file. To do so, select the project reference that points to the assembly. In the Properties window, set Copy Local to false. Next, make sure the assembly is copied to the same location as your website. If you’re using an ASP.NET test website, that means you must add the assembly to the ClientBin folder in the test website. (You can’t try this example with a simple HTML test page, because WebClient doesn’t work when you run a Silverlight application
from the file system.)

To implement on-demand downloading of assemblies, you need to use the WebClient class you saw earlier, in conjunction with the AssemblyPart class. The WebClient retrieves the assembly, and the AssemblyPart makes it available for downloading:

string uri = Application.Current.Host.Source.AbsoluteUri;
int index = uri.IndexOf("/ClientBin");
// In this example, the URI includes the /ClientBin portion, because we've
// decided to place the DLL in the ClientBin folder.
uri = uri.Substring(0, index) + "/ClientBin/ResourceClassLibrary.dll";
// Begin the download.
WebClient webClient = new WebClient ();
webClient.OpenReadCompleted += webClient_OpenReadCompleted;
webClient.OpenReadAsync(new Uri(uri));
When the assembly is downloaded, you use the AssemblyPart.Load() method to load it into
the current application domain:
private void webClient_OpenReadCompleted (object sender,
OpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
// (Add code to display error or degrade gracefully.)
}
else
{
AssemblyPart assemblypart = new AssemblyPart();
assemblypart.Load(e.Result);
}
}

Supporting Assembly Caching
As you learned, assembly caching is a feature that allows Silverlight to download class library assemblies and store them in the browser cache. This way, these assemblies don’t need to be downloaded every time the application is launched.

By default, the assemblies you build won’t support assembly caching. However, you can add this support by satisfying two requirements. First, your assembly must have a strong name. Second, your assembly needs a special type of XML file that describes its contents, called an .extmap.xml file. The following sections walk you through both requirements, and you can refer to the downloadable code for this chapter to assembly caching in action with a custom assembly.

The Strong Key Name
To support assembly caching, your class library assembly needs a strong name, which will uniquely identify it in the browser cache and prevent naming conflicts. To create a strong key for your assembly, follow these steps:

1. Double-click the Properties item in the Solution Explorer.
2. Click the Signing tab.
3. Select the “Sign the assembly” option.
4. In the “Choose a strong key name” list, choose to show the Create Strong Name
Key dialog box.
5. To finish creating your key, you’ll need to supply a file name (like MyKey.snk) and,
optionally, a password.
5.      Click OK. Visual Studio will create the new key file and add it to your class library project.

This creates a strong key file and uses it for your assembly. From this point on, every time you compile your project, Visual Studio uses the strong key to sign the final assembly. Before you can continue to the next step, you need to know public key token of the key pair that’s used to sign your assembly. Unfortunately, Visual Studio doesn’t provide an easy way to get this information (at least not without a plug-in of some sort). Instead, you need to resort to the sn.exe command-line tool. First, choose Microsoft Visual Studio 2010 Visual Studio Tools Visual Studio Command Prompt. Once you’ve loaded the Visual Studio command prompt, change to the directory that holds your key file. Then, run the following two commands (replacing MyKey.snk with the name of your key):

sn –p MyKey.snk MyKey.bin
sn –t MyKey.bin

When you complete the second command, you’ll see a message like this:
Microsoft (R) .NET Framework Strong Name Utility Version 3.5.30729.1
Copyright (c) Microsoft Corporation. All rights reserved.
Public key token is e6a351dca87c1032

The bold part is the piece of information you need for the next step: creating a .extmap.xmlfile for your assembly.

The .extmap.xml File
The .extmap.xml file is an ordinary text file that holds XML content. It’s named to match your assembly. For example, if you have a class library assembly named CacheableAssembly.dll, you’ll need to create a file named CacheableAssembly.extmap.xml. The presence of this file tells Silverlight that your assembly supports assembly caching. To make life easy, you can add the .extmap.xml file to your class library project. Select it in the Solution Explorer, and set Build Action to None and the Copy to Output Directory setting to “Copy always.” This ensures that the file will be placed in the same directory as your assembly file when you compile it. Figure shows a class library with the appropriate .extmap.xml file.






The easiest way to create an .extmap.xml file is to take a sample (like the one shown next), and modify it for your assembly. In the following listing, the details you need to change are in bold:

<?xml version="1.0"?>
<manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<assembly>
<name>CacheableAssembly</name>
<version>1.0.0.0</version>
<publickeytoken>e6a351dca87c1032</publickeytoken>
<relpath>CacheableAssembly.dll</relpath>
<extension downloadUri="CacheableAssembly.zip" />
</assembly>
</manifest>

The name and version details are obvious, and they should match your assembly. The public key token is the identifying fingerprint of the strong key that was used to sign your assembly, and you collected it with the sn.exe tool in the previous section. The relative path (relpath) is the exact file name of the assembly. Finally, the downloadUri attribute provides the most important piece of information—it tells the application where to find the packaged, downloadable assembly.


You have two options for setting downloadUri. The easiest approach is the one that’s used in the previous example—simply supply a file name. When you switch on assembly caching in your application, Visual Studio will take your class library assembly (in this case, CacheableAssembly.dll), compress it, and place the compressed file (in this case, CacheableAssembly.zip) alongside the compiled XAP file. this is the approach that Silverlight’s add-on assemblies use.

Your other option is to use an absolute URI for the downloadUri:
<extension
downloadUri="http://www.mysite.com/assemblies/v1.0/CacheableAssembly.zip" />

In this case, Visual Studio won’t package up the assembly when you compile the application. Instead, it expects you to have already placed the assembly at the web location you’ve specified. This gives you a powerful way to share libraries between multiple applications. However, the download location must be on the same domain as the Silverlight application, or it must explicitly allow cross-domain access. With the .extmap.xml file shown earlier, you’re ready to use assembly caching. To try it, create an application that uses your class library. Turn on assembly caching for your application by opening the project properties and selecting the “Reduce XAP size by using
application library caching” option. Finally, build your application. If you check out the contents of your Debug folder, you’ll find the packaged up ZIP file for your assembly (as shown
in Figure)





ASP.NET Web Services
Some of the most interesting Silverlight applications have a hidden backbone of server-side
code. They may call a web server to retrieve data from a database, perform authentication, store
data in a central repository, submit a time-consuming task, or perform any number of other
tasks that aren’t possible with client-side code alone. The common ingredient in all these
examples is that they are based on web services—libraries of server-side logic that any webcapable
application can access.
In this chapter, you’ll learn how to create ASP.NET web services and call them from a
Silverlight application. You’ll learn how to deal with different types of data, handle security, tap
into ASP.NET services, monitor the client’s network connection, and even build a two-way web
service that calls your application when it has something to report.

Building Web Services for Silverlight
Without a doubt, the most effective way for a Silverlight application to tap into server-side code is through web services. The basic idea is simple: you include a web service with your ASP.NET website, and your Silverlight application calls the methods in that web service. Your web services can provide server-generated content that isn’t available on the client (or would be too computationally expensive to calculate). Or, your web services can run queries and perform updates against a server-side database. With a little extra work, it can
even use ASP.NET services such as authentication, caching, and session state.
Silverlight applications can call traditional ASP.NET web services (.asmx services) as well as
the WCF services, which are the newer standard. In the following sections, you’ll learn how to
build, call, and refine a WCF service.

Creating a Web Service
To create a WCF service in Visual Studio, right-click your ASP.NET website in the Solution
Explorer, and choose Add New Item. Choose the Silverlight-enabled WCF Service template,
enter a file name, and click Add.
When you add a new WCF service, Visual Studio creates two files (see Figure )

The service endpoint: The service endpoint has the extension .svc and is placed in your root website folder. For example, if you create a web service named TestService, you get a file named TestService.svc. When using the web service, the client requests a URL that points to the .svc file. But the .svc file doesn’t contain any code—it includes one line of markup that tells ASP.NET where to find the corresponding web service code.

The service code: The service code is placed in the App_Code folder of your website (if you’re creating a projectless website) or in a separate code-behind file (if you’re creating a web project). For example, if you create a web service named TestService, you get a code file named TestService.cs in a projectless website or TestService.svc.cs in a web project. Either way, the contents are the same: a code file with a class that implements the service interface and provides the actual code for your web service.



The code file for your web service begins with two attributes. The ServiceContract attribute indicates that it defines a service contract—in other words, a set of methods that you plan to expose to remote callers as part of a service. The AspNetCompatibilityRequirements attribute indicates that it will have access to ASP.NET platform features such as session state:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{ ... }

To add a new web service method, you add a new method to the code file and make sure it’s decorated with the OperationContract attribute. For example, if you want to add a method that returns the current time on the server, you can modify the interface like this:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
[OperationContract]
public DateTime GetServerTime()
{
return DateTime.Now;
}
}

Initially, a newly created service contains a single DoWork() web service method, which
Visual Studio adds as an example. You’re free to delete or customize this method.

Adding a Service Reference
You consume a web service in a Silverlight application in much the same way that you consume
one in a full-fledged.NET application. The first step is to create a proxy class by adding a Visual
Studio service reference.

To add the service reference, follow these steps:
1. Right-click your Silverlight project in the Solution Explorer, and choose Add Service
Reference. The Add Service Reference dialog box appears (see Figure).



2. In the Address box, enter the URL that points to the web service, and click Go. However, you probably won’t know the exact URL of your web service, because it incorporates the randomly chosen port used by Visual Studio’s test web server (as in http://localhost:4198/ASPWebSite/TestService.svc). You could run your web application to find out, but an easier approach is to click the Discover button, which automatically finds all the web services that are in your current solution.

3. In the Namespace box, enter the C# namespace that Visual Studio should use for the automatically generated classes. This namespace is created inside your project namespace. So if your project is MyClient and you give the web service the namespace name WebServiceSite, the full namespace is MyClient.WebServiceSite.

4. Click OK. Visual Studio creates a proxy class that has the code for calling the web service. To see the file that contains this code, select the Silverlight project in the Solution Explorer, click the Show All Files button, expand the namespace node (which uses the name you picked in step 3), then expand the Service References node inside, then expand the Reference.svcmap node inside that, and open the Reference.cs file. When you add a service reference, Visual Studio creates a proxy class—a class that you can interact with to call your web service. The proxy class is named after the original web service class with the word Client added at the end.
For example, when adding a reference to the TestService shown earlier, Visual Studio creates a proxy class named TestServiceClient. The proxy class contains methods that allow you to trigger the appropriate web service calls and all the events that allow you to receive the results. It takes care of the heavy lifting (creating the request message, sending it in an HTTP request, getting the response, and then notifying your code).

You can update your service reference at any time to taken into account web service changes (such as new methods or changes to the number of type of method parameters). To do so, recompile the web application, then right-click the service reference in the Solution Explorer, and finally choose Update Service Reference.

Silverlight includes a command-line utility that does the same work as Visual Studio’s service reference feature. This utility is named slsvcutil.exe (for Silverlight Service Model Proxy Generation Tool), and you can run it most easily from the Visual Studio Command Prompt. For example, the following command creates the proxy code for TestService example shown earlier (assuming the port number matches the port that the test web server is currently using):

slsvcutil http://localhost:4198/ASPWebSite/TestService.svc?WSDL

The ?WSDL that’s appended to the service is an web service convention. It tells ASP.NET to provide the Web Service Description Language (WSDL) document that describes the web service. This document details the public interface of the web service (its methods and parameters) but doesn’t expose any private details about its code or inner workings. The WSDL document has all the information Visual Studio or slsvcutil needs to generate the proxy code.

Calling the Web Service
To use the proxy class, start by importing the namespace that you specified for the service reference in step 3. Assuming that you used the namespace MyWebServer and your project is named MySilverlightProject, you’d need this statement:
using MySilverlightProject.MyWebServer;

In Silverlight, all web service calls must be asynchronous. That means you call a method to start the call (and send off the request). This method returns immediately. Your code can then carry on to perform other tasks, or the user can continue to interact with the application. When the response is received, the proxy class triggers a corresponding proxy class event, which is named in the form MethodNameCompleted. You must handle this event to process the results.
Here’s how to call the TestService.GetServerTime() method shown earlier:
// Create the proxy class.
TestServiceClient proxy = new TestServiceClient();
// Attach an event handler to the completed event.
proxy.GetServerTimeCompleted += new
EventHandler<GetServerTimeCompletedEventArgs>(GetServerTimeCompleted);
// Start the web service call.
proxy.GetServerTimeAsync();

To get the results, you need to handle the completed event and examine the corresponding EventArgs object. When generating the proxy class, Visual Studio also creates a different EventArgs class for each method. The only difference is the Result property, which is typed to match the return value of the method. For example, the GetServerTime() method works in conjunction with a GetServerTimeCompletedEventArgs class that provides a DateTime object through its Result property.

When accessing the Result property for the first time, you need to use exception-handling code. That’s because this is the point where an exception will be thrown if the web service call failed—for example, the server couldn’t be found, the web service method returned an error, or the connection timed out. (As an alternative, you could check the Error property of the custom EventArgs object. For example, if GetServerTimeCompletedEventArgs.Error is null, no error occurred while processing the request, and it’s safe to get the data from the Result property.) Here’s an event handler that reads the result (the current date and time on the server) and displays it in a TextBlock:

private void GetServerTimeCompleted(object sender,
GetServerTimeCompletedEventArgs e)
{
try
{
lblTime.Text = e.Result.ToLongTimeString();
}
catch (Exception err)
{
lblTime.Text = "Error contacting web service";
}
}

By default, the proxy class waits for one minute before giving up if it doesn’t receive a response. You can configure the timeout length by using code like this before you make the web service call:
proxy.InnerChannel.OperationTimeout = TimeSpan.FromSeconds(30);

Configuring the Web Service URL
When you add a service reference, the automatically generated code includes the web service URL. As a result, you don’t need to specify the URL when you create an instance of the proxy class.
But this raises a potential problem. All web service URLs are fully qualified—relative paths aren’t allowed. If you’re using the test web server in Visual Studio, that means you’ll run into trouble if you try to run your application at a later point, when the test web server has chosen a different port number. Similarly, you’ll need to update the URL when you deploy your final application to a production web server. You can solve this problem by updating the service reference (and thereby regenerating all the proxy code), but there are two easier options.

Your first option is to configure Visual Studio to always use a specific port when running its test web server with your web application. This works only if you’ve created your web application as a web project (not a projectless website). In this case, you can configure the test web server for your project by double-clicking the Properties item in the Solution Explorer. Choose the Web tab. Then, in the Servers section, select “Specific port” and enter the port number you’d like to use. (You may as well choose the port number that the test server is already using for this session.) In the settings shown in Figure, that port number is 54752.



Now you can modify the code that creates your proxy class. Instead of simply using this, which assumes the service is at the same port that it occupied when you added the reference:

TestServiceClient proxy = new TestServiceClient();
You can explicitly set the port with the EndpointAddress class:
// Create the proxy class.
TestServiceClient proxy = new TestServiceClient();
// Use the port that's hard-coded in the project properties.
EndpointAddress address = new EndpointAddress(
"http://localhost:54752/ASPWebSite/TestService.svc");
// Apply the new URI.
proxy.Endpoint.Address = address;

Your second option is to change the address dynamically in your code so that it’s synchronized with the port number that the test web server is currently using. To do so, you simply need to grab the URL of the Silverlight page and find its port number (because the Silverlight page is hosted on the same web server as the web service). Here’s the code that does the trick:

// Create a new URL for the TestService.svc service using the current port number.
EndpointAddress address = new EndpointAddress("http://localhost:" +
HtmlPage.Document.DocumentUri.Port + "/ASPWebSite/TestService.svc");
// Use the new address with the proxy object.
TestServiceClient proxy = new TestServiceClient();
proxy.Endpoint.Address = address;

You can use similar code to create a URL based on the current Silverlight page so that the web service continues to work no matter where you deploy it, as long as you keep the web service and Silverlight application together in the same web folder.

_________________________________________________________________________________
Reach us At: - 0120-4029000; 0120-4029024; 0120-4029025, 0120-4029027; 0120-4029029
Mbl: 9953584548
Write us at: - Smruti@apextgi.com and pratap@apextgi.com










No comments:

Post a Comment