silverlight 2 hands-on lab · page 3 of 15 the adventureworks product search screen is a part of...

15
Page 1 of 15 Silverlight 2 Hands-on Lab Application Partitioning Contents Set up ........................................................................................................................................................ 2 Exercise 1: Application Partitioning ......................................................................................................... 2 Additional Resources and Labs ............................................................................................................... 15

Upload: others

Post on 28-Sep-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 1 of 15

Silverlight 2 Hands-on Lab

Application Partitioning

Contents Set up ........................................................................................................................................................ 2

Exercise 1: Application Partitioning ......................................................................................................... 2

Additional Resources and Labs ............................................................................................................... 15

Page 2: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 2 of 15

Silverlight 2 Hands-on Labs

Set up Install the following software components on Windows Vista machine with at least 2GB RAM:

1. Visual Studio 2008

2. SQL Server 2008 Express

a. AdventureWorks Sample Database (http://www.codeplex.com/MSFTDBProdSamples)

3. ASP.NET Extensions preview (http://asp.net/downloads/3.5-extensions/)

4. Silverlight Developer Tools (http://silverlight.net/GetStarted)

a. Silverlight 2.0 Beta 2 Runtime

b. Silverlight 2.0 Beta 2 SDK

c. Silverlight 2.0 templates for Visual Studio 2008

Exercise 1: Application Partitioning

Since In this post we will look at one of the architectural aspects of the enterprise class applications - application partitioning. Application partitioning is done for variety of reasons including the following:

To optimize download times To chunk the application down to a set of manageable deployment units To isolate sensitive parts of the application from the anonymous parts To get loosely coupled integration with external applications To bridge the differences between the development model and the deployment model

To help with application partitioning, Silverlight 2 allows the creation of multiple deployment units with each unit packaged into a file with .XAP extension. The core runtime provides network, IO and reflection libraries to create type system artifacts from the byte code streams embedded in the XAP packages. For example, sets of related user UserControls may be packed together into their respective packages and deployed on same or multiple web sites.

We will look at this from a simple application that searches AdventureWorks data extracted into an object list. The object list List<ProductInfo> is embedded in one of the packages to make the application a self contained solution. The following is the schematic of the solution:

Page 3: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 3 of 15

The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application

built with Silverlight 2. The above picture shows that the main Silverlight package (InventoryMain.xap)

is deployed on Inventory_Web site while the details package (InventoryDetails.xap) is deployed on

InventoryDetails_web site. The product search screen will be composed of two UserControls -

Page.xaml located inside InventoryMain.xap and ProductListView.xaml packaged inside

InventoryDetails.xap.

Here are the detailed steps:

1. Create a blank Visual Studio solution (named AppPart) using "Visual Studio Solution" template.

This template is located inside other project types category located on the "Add New Project"

dialog.

2. Create two Silverlight projects: InventoryMain and InventoryDetails using VS2008 "Silverlight

Application" template. During the creation of these projects, the template will ask you to create

a web site to map each of the projects. Map InventoryMain to Inventory_Web site and

InventoryDetails to InventoryDetails_Web site. Select "ASP.NET Web Application" template for

these sites. The "ASP.NET Web Application" template will allow us to use a fixed port number.

The completed Solution Explorer will look like the screen shown:

Page 4: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 4 of 15

3. Change the port numbers of the projects from their defaults to (Inventory_Web:1071,

InventoryDetails:1072) from the web application project property pages using the Web tab.

4. Change the InventoryMain.Page.xaml to have the following XAML:

<!--this is sample code; only meant for demo purpose and not for production use-->

<UserControl xmlns:my="clr-

namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

x:Class="InventoryMain.Page"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400"

Height="336"

>

<Border BorderBrush="Blue" BorderThickness="2" CornerRadius="5,5,5,5"

Margin="5,5,5,5">

Page 5: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 5 of 15

<Grid x:Name="LayoutRoot" Background="White">

<Grid.Resources>

<Style x:Key="LabelStyle" TargetType="TextBlock">

<Setter Property="FontFamily" Value="Verdana"/>

<Setter Property="FontSize" Value="20"/>

<Setter Property="Foreground" Value="Blue"/>

</Style>

</Grid.Resources>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="320"/>

<ColumnDefinition Width="*"/>

</Grid.ColumnDefinitions>

<Canvas Grid.Column="0">

<TextBlock Text="AdventureWorks Product Search" Canvas.Left="40"

Canvas.Top="8" Style="{StaticResource LabelStyle}"/>

<StackPanel Background="LightSteelBlue" Height="250" Width="320"

Canvas.Left="40" Canvas.Top="40">

<TextBlock Text="Search By Product Name" HorizontalAlignment="Center"

Height="25"/>

<TextBox x:Name="textSearchCriteria" Width="175" Height="25"

HorizontalAlignment="Center" Margin="10,2,0,1"/>

<Button x:Name="buttonSubmitSearch" Content="Submit search"

Width="150" HorizontalAlignment="Center" Margin="10,2,0,1"

Click="buttonSubmitSearch_Click"/>

</StackPanel>

<TextBlock Text="Search Status:" Foreground="Blue" Height="22.537"

Margin="0,0,0,0" Canvas.Top="250" Canvas.Left="60.384"/>

<TextBlock x:Name="textStatus" Text="OK" Foreground="Red" Canvas.Top="250"

Canvas.Left="168" RenderTransformOrigin="2.14499998092651,-1.06500005722046"

Width="168" Height="62.537"/>

</Canvas>

<Canvas Grid.Column="1">

<StackPanel x:Name="searchResultsPanel" Canvas.Left="40" Canvas.Top="40"

Width="320" Height="250" Background="Khaki" Visibility="Collapsed">

<TextBlock Text="Search Results" Height="25"

HorizontalAlignment="Center"/>

</StackPanel>

</Canvas>

</Grid>

</Border>

</UserControl>

5. Add InventoryMain.ProductInfo.cs to have the following content:

using System;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

namespace InventoryMain

{

public class ProductInfo

Page 6: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 6 of 15

{

public int _productID;

public string _productName;

public string _productNumber;

public int _productSafetyStockLevel;

public int _productReorderPoint;

public int ProductID

{

get { return this._productID; }

set { this._productID = value; }

}

public string ProductName

{

get { return this._productName; }

set { this._productName = value; }

}

public string ProductNumber

{

get { return this._productNumber; }

set { this._productNumber = value; }

}

public int ProductSafetyStockLevel

{

get { return this._productSafetyStockLevel; }

set { this._productSafetyStockLevel = value; }

}

public int ProductReorderPoint

{

get { return this._productReorderPoint; }

set { this._productReorderPoint = value; }

}

}

}

6. Add InventoryMain.PackageUtil.cs to contain the following code:

//this is sample code; only meant for demo purpose and not for production

use

using System;

using System.Collections.Generic;

using System.Windows;

using System.Windows.Markup;

using System.Windows.Resources;

using System.Reflection;

using System.Net;

using System.IO;

using System.Xml;

using System.Xml.Linq;

namespace InventoryMain

{

//extracts various artifacts from the package stream

Page 7: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 7 of 15

public class PackageUtil

{

public static Assembly LoadAssemblyFromXap(Stream packageStream,

string

assemblyName)

{

string appManifestString =

new StreamReader(Application.GetResourceStream(

new StreamResourceInfo(packageStream, null),

new Uri("AppManifest.xaml", UriKind.Relative)).Stream)

.ReadToEnd();

Deployment deployment =

(Deployment)XamlReader.Load(appManifestString);

Assembly asm = null;

foreach (AssemblyPart assemblyPart in deployment.Parts)

{

if (assemblyPart.Source == assemblyName)

{

string source = assemblyPart.Source;

StreamResourceInfo streamInfo =

Application.GetResourceStream(

new StreamResourceInfo(packageStream,

"application/binary"),

new Uri(source,

UriKind.Relative));

asm = assemblyPart.Load(streamInfo.Stream);

break;

}

}

return asm;

}

}

//abstracts the WebClient

public class SLPackage

{

private Uri _packageUri;

public class PackageEventArgs : EventArgs

{

private Stream _packageStream;

private string _packageUri;

public PackageEventArgs(Stream packageStream, string

packageUri)

{

this._packageStream = packageStream;

this._packageUri = packageUri;

}

public Stream PackageStream { get { return _packageStream; } }

public String PackageUri { get { return _packageUri; } }

}

public delegate void PackageEventHandler(object sender,

PackageEventArgs e);

public event PackageEventHandler PackageDownloaded;

Page 8: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 8 of 15

public SLPackage(Uri uri)

{

_packageUri = uri;

}

public void LoadPackage()

{

WebClient webClient = new WebClient();

webClient.OpenReadCompleted +=

new

OpenReadCompletedEventHandler(webClient_OpenReadCompleted);

webClient.OpenReadAsync(_packageUri);

}

private void webClient_OpenReadCompleted(object sender,

OpenReadCompletedEventArgs e)

{

PackageEventArgs pe = null;

try

{

pe = new PackageEventArgs(e.Result,

this._packageUri.OriginalString);

}

catch

{

PackageDownloaded(this, null);

return;

}

PackageDownloaded(this, pe);

}

}

}

The PackageUtil class abstracts the functionality in the XAML controls that download the packages. If a

package is on a different domain than the originating domain of the XAP, and if a valid policy file (i.e.,

clientaccesspolicy.xml) is not deployed on the 2nd domain, the WebClient.OpenReadAsync will never

throw an exception. However the called delegate (in this case webClient_OpenReadCompleted) will throw

a ProtocolException which may indicate a problem with the policy file or accessing the remote resource.

The delegate method catches all the exceptions and triggers the PackageDownloaded event with a null

PackageEventArgs argument. It will be the responsibility of the downloader class (in this case

InventoryMain.Page.xaml user control) to verify the null stream and take appropriate corrective

measures.

7. Modify the InventoryMain.Page.xaml.cs to have the following code:

//this is sample code; only meant for demo purpose and not for production use

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

Page 9: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 9 of 15

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Reflection;

namespace InventoryMain

{

public partial class Page : UserControl

{

private bool detailsLoaded =false;

private Uri packageUri =

new Uri("http://localhost:1072/ClientBin/InventoryDetails.xap",

UriKind.Absolute);

public Page()

{

InitializeComponent();

}

private void buttonSubmitSearch_Click(object sender, RoutedEventArgs e)

{

//if not already loaded load the package

//Get a reference to the control and add it to the children

searchResultsPanel.DataContext =

DataUtil.GetInventoryInfoByName(this.textSearchCriteria.Text);

if (!detailsLoaded)

{

SLPackage detailsPackage;

detailsPackage = new SLPackage(packageUri);

detailsPackage.PackageDownloaded += new

SLPackage.PackageEventHandler(LoadDetailsGrid);

detailsPackage.LoadPackage();

this.textStatus.Text = "Loading...";

}

}

void LoadDetailsGrid(object sender, SLPackage.PackageEventArgs e)

{

if (e == null)

{

textStatus.Text = "Fatal package load error!!!";

return;

}

Assembly asm = PackageUtil.LoadAssemblyFromXap(e.PackageStream,

"InventoryDetails.dll");

object uc = asm.CreateInstance("InventoryDetails.ProductListView");

this.searchResultsPanel.Children.Add((UIElement)uc);

this.textStatus.Text = "OK";

detailsLoaded = true;

this.Width = 740;

this.searchResultsPanel.Visibility = Visibility.Visible;

}

}

}

Because of the sandbox in which the Silverlight runtime operates, all network operations are

asynchronous in nature. This will give the Silverlight runtime better control in terms of monitoring the

Page 10: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 10 of 15

runaway applications. Downloading of the package is abstracted inside SLPackage class which can cache

the package stream if necessary and use it for extracting multiple resources. In this version of

SLPackage, the field _packageStream is not populated as I did not need it. You can easily modify the

webClient_OpenReadCompleted delegate method to populate the reference to the package stream.

Also, look at the following code Click handler:

private void buttonSubmitSearch_Click(object sender, RoutedEventArgs e)

{

//if not already loaded load the package

//Get a reference to the control and add it to the children

searchResultsPanel.DataContext =

DataUtil.GetInventoryInfoByName(this.textSearchCriteria.Text);

if (!detailsLoaded)

{

SLPackage detailsPackage;

detailsPackage = new SLPackage(packageUri);

detailsPackage.PackageDownloaded += new

SLPackage.PackageEventHandler(LoadDetailsGrid);

detailsPackage.LoadPackage();

this.textStatus.Text = "Loading...";

}

}

Since LoadPackage() returns immediately the tendency is to wait for the asynchronous operation to

complete with a mutex or similar thread synchronization object. But this is not recommended as this

will block the UI thread and will not receive any asynchronous thread messages posted by the WebClient

asynchronous read operation result and in turn the SLPackage.PackageDownloaded event.

The processing of the downloaded package (extraction of resources, UserControls, composition of UI

from these controls and resources) should be synchronized with the download completion event. When

the download is complete, SLPackage causes a PackageDownloaded event which will invoke

LoadDetailsGrid delegate method. LoadDetailsGrid is responsible for the extraction of the assembly

reference containing the “InventoryDetails.ProductListView” UserControl and load it into the visual

tree of the InventoryMain.Page.

The state flows into the new control through the DataContext property set to its parent

(searchResultsPanel) inside buttonSubmitSearch_Click handler through the following code fragment:

searchResultsPanel.DataContext =

DataUtil.GetInventoryInfoByName(this.textSearchCriteria.Text);

Implement DataUtil.GetInventoryInfoByName using LINQ and the inline List<ProductInfo> created from

the data extracted from AdventureWorks database (which is not necessary for testing the code). Add

the DataUtil class to InventoryMain project using the following code:

Page 11: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 11 of 15

//this is a sample code; only meant for demo purpose only and not for

production use

using System;

using System.Linq;

using System.Xml;

using System.Xml.Linq;

using System.Collections;

using System.Collections.Generic;

namespace InventoryMain

{

public class DataUtil

{

public static IEnumerable<ProductInfo> GetInventoryInfoByName(string

productName)

{

List<ProductInfo> productData = GetSampleData();

var products = from product in productData

where product.ProductName.StartsWith(productName)

select product;

return products;

}

public static List<ProductInfo> GetSampleData()

{

List<ProductInfo> products = new List<ProductInfo>();

products.Add(new ProductInfo { ProductID = 341, ProductName = "Flat

Washer 1", ProductNumber = "FW-1000", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 342, ProductName = "Flat

Washer 6", ProductNumber = "FW-1200", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 343, ProductName = "Flat

Washer 2", ProductNumber = "FW-1400", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 344, ProductName = "Flat

Washer 9", ProductNumber = "FW-3400", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 345, ProductName = "Flat

Washer 4", ProductNumber = "FW-3800", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 346, ProductName = "Flat

Washer 3", ProductNumber = "FW-5160", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 347, ProductName = "Flat

Washer 8", ProductNumber = "FW-5800", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 348, ProductName = "Flat

Washer 5", ProductNumber = "FW-7160", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 349, ProductName = "Flat

Washer 7", ProductNumber = "FW-9160", ProductSafetyStockLevel = 1000,

ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 350, ProductName = "Fork

Crown", ProductNumber = "FC-3654", ProductSafetyStockLevel = 800,

ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 351, ProductName =

"Front Derailleur Cage", ProductNumber = "FC-3982", ProductSafetyStockLevel =

800, ProductReorderPoint = 600 });

Page 12: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 12 of 15

products.Add(new ProductInfo { ProductID = 352, ProductName =

"Front Derailleur Linkage", ProductNumber = "FL-2301", ProductSafetyStockLevel

= 800, ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 355, ProductName =

"Guide Pulley", ProductNumber = "GP-0982", ProductSafetyStockLevel = 800,

ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 356, ProductName = "LL

Grip Tape", ProductNumber = "GT-0820", ProductSafetyStockLevel = 800,

ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 357, ProductName = "ML

Grip Tape", ProductNumber = "GT-1209", ProductSafetyStockLevel = 800,

ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 358, ProductName = "HL

Grip Tape", ProductNumber = "GT-2908", ProductSafetyStockLevel = 800,

ProductReorderPoint = 600 });

products.Add(new ProductInfo { ProductID = 359, ProductName =

"Thin-Jam Hex Nut 9", ProductNumber = "HJ-1213", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 360, ProductName =

"Thin-Jam Hex Nut 10", ProductNumber = "HJ-1220", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 361, ProductName =

"Thin-Jam Hex Nut 1", ProductNumber = "HJ-1420", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 362, ProductName =

"Thin-Jam Hex Nut 2", ProductNumber = "HJ-1428", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 363, ProductName =

"Thin-Jam Hex Nut 15", ProductNumber = "HJ-3410", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 364, ProductName =

"Thin-Jam Hex Nut 16", ProductNumber = "HJ-3416", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 365, ProductName =

"Thin-Jam Hex Nut 5", ProductNumber = "HJ-3816", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 366, ProductName =

"Thin-Jam Hex Nut 6", ProductNumber = "HJ-3824", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 367, ProductName =

"Thin-Jam Hex Nut 3", ProductNumber = "HJ-5161", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 368, ProductName =

"Thin-Jam Hex Nut 4", ProductNumber = "HJ-5162", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 369, ProductName =

"Thin-Jam Hex Nut 13", ProductNumber = "HJ-5811", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 370, ProductName =

"Thin-Jam Hex Nut 14", ProductNumber = "HJ-5818", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 371, ProductName =

"Thin-Jam Hex Nut 7", ProductNumber = "HJ-7161", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 372, ProductName =

"Thin-Jam Hex Nut 8", ProductNumber = "HJ-7162", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 373, ProductName =

"Thin-Jam Hex Nut 12", ProductNumber = "HJ-9080", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

products.Add(new ProductInfo { ProductID = 374, ProductName =

"Thin-Jam Hex Nut 11", ProductNumber = "HJ-9161", ProductSafetyStockLevel =

1000, ProductReorderPoint = 750 });

Page 13: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 13 of 15

return products;

}

}

}

Note: In order for the above code to compile, you need to add System.Xml.Linq.dll to the

InventoryMain’s reference list. Because our main application will be loading another assembly that

references the DataGrid, we will want to add a reference to System.Windows.Controls.Data in

InventoryMain as well. This will prevent us from having to load it independently as well.

Now we will focus on the InventyoryDetails project.

1. Let us remove the default Page.xaml and add a “Silverlight User Control” and name it

ProductListView.xaml.

2. Replace the default markup with the following XAML:

<!--this is sample code; only meant for demo purpose and not for production

use-->

<UserControl x:Class="InventoryDetails.ProductListView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:data="clr-

namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

>

<data:DataGrid x:Name="dataGridProductListBase" ItemsSource="{Binding}"

Height="225" Width="320" VerticalAlignment="Top"

AutoGenerateColumns="True" VerticalScrollBarVisibility="Auto"

HorizontalScrollBarVisibility="Auto"/>

</UserControl>

Notice how we are referencing the xmlns:data for using the DataGrid. We need to add a reference in

our Silverlight application to System.Windows.Controls.Data in order to compile. One additional

change we need to make as well is changing our App.xaml.cs file. Since we deleted Page.xaml (and thus

the Page class), we need to change the RootVisual that gets loaded. Open App.xaml.cs in

InventoryDetails and change the startup line of code to:

this.RootVisual = new ProductListView();

We are finished with the details UserControl. This is merely the skin. Pay close attention to the

attribute ItemsSource="{Binding}" in the above markup as this attribute tells the data binding engine to

pick up the data from the object (in this case List<ProductInfo>) bound to the DataContext. In the

absence of this attribute, the DataGrid will be empty even if the search output results in a number of

products.

Page 14: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 14 of 15

3. Compile the project and test it by choosing the InventoryMainTestPage.html in Inventory_Web

and choosing “View in Browser” (http://localhost:1071/InventoryMainTestPage.html). Use

“Thin” as the search criteria. We will see the following screen or similar errors in Visual Studio:

4. InventoryMain.xap package originated from http://localhost:1071/ and is trying to access

InventoryDetails.xap from http://localhost:1072/ domain. This action requires cross-domain

activity. WebClient embedded inside SLPackage looks for clientaccesspolicy.xml for any policies

that allows the first domain to access http://locahost:1072/ domain’s resources. Deploy the

following clientaccesspolicy.xml to the root folder of InventoryDetails_Web project:

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

<cross-domain-access>

<policy>

<allow-from http-request-headers="*">

<domain uri="http://localhost:1071"/>

</allow-from>

<grant-to>

<resource path="/" include-subpaths="true"/>

</grant-to>

</policy>

</cross-domain-access>

</access-policy>

Page 15: Silverlight 2 Hands-on Lab · Page 3 of 15 The AdventureWorks Product Search screen is a part of the fictitious Inventory Manager application built with Silverlight 2. The above picture

Page 15 of 15

5. Recompile the project and test it by accessing

http://localhost:1071/InventoryMainTestPage.html. If you had followed all the steps, you

should see the following screen:

DataGrid in the above view is generating default columns… this can easily be changed by applying

templates.

One important note before we close is the caching of XAP packages. WebClient will open the stream to the package from the browser cache if it is already downloaded. If the package is not in the cache, Silverlight runtime with the help of the browser sandbox, verifies the cross-domain policies, downloads the package, caches locally (assuming that there no cache-control: private kind of headers in the response) and hands over the stream to the application code through utility classes like SLPackage.

Additional Resources and Labs Be sure to visit the Silverlight community site at http://silverlight.net to learn more about Silverlight 2,

access more hands-on labs, How-do-I videos and tutorials, and participate in the Forums to ask

questions (over 36,000 questions answered).