End-to-End Data Centric Application with Silverlight 2

I have been having some fun with an end to end Silverlight 2 demo recently and I thought I'd share it here.   My goal with the demo is to show how easy it is to create an end to end Silverlight application.  In particular, my goal is to show

  1. Explain the Silverlight Project Format
  2. How to do rich layout and animation
  3. Uses line of business controls for Silverlight such as DataGrid
  4. Has a Linq based data layer on the server on the server
  5. Exposes business logic over that data via a WCF web service
  6. Consume the service on the client in Silverlight and databind to the DataGrid
  7. Store result locally to minimize round trips to the server across instantiations with IsolatedStorage
  8. Re-theme the UI to make it look more cool.
  9. Do it all in code that you could easily write on stage in about 30-45 mins
  10. Have Fun!

 

Download the completed sample (VB one is available as well)

 

Here is a screen show of what we are going to end up with..

image

 

I. Create the Silverlight Project

In VS2008 with the Silverlight 2 Tools for Silverlight installed, create a new Silverlight application

image

 

image

VS asks you to create a home web site for your Silverlight application.  This is important because we are going to implement our data access layer and web services layer in this web site. 

What VS creates for you looks like:

image

The web project contains an ASP.NET page that gives you already wired up to the Silverlight application.    Notice we use the new ASP.NET Silverlight control here to host rich silverlight content within your ASP.NET page. 

         <asp:Silverlight ID="Xaml1" runat="server" 
            Source="~/ClientBin/EndToEndSilverlightDemo.xap"
            Version="2.0" Width="100%" Height="100%" />

There is also a plain-old HTML page that you can host on any web server (Apache, etc)..  Nothing in Silverlight requires ASP.NET or even IIS on the server.

Notice the EndToEndSilverlightDemo.xap file?  This is the client side silverlight application.  The .xap file is just a zip file format.  So in fact if you just rename it to .zip, you can easily see inside. 

image

image

What we see here is the Manifest for the Silverlight application, the actual C# or VB code you write for the application and then the parts of the framework your application needs.  By Silverlight RTM, many of controls will be rolled into the core so you don't have to include them in your application.

 

 

II. Rich Layout

Let's start with some very basic Silverlight coding.  In page.xaml, let's start easy and just add a button.

image

Now, that button defaults to filling the entire grid, so let's give it a size, and some text...

image

As an aside, it is interesting to note that the property label on the button is called "Content" rather than "Text" or something like that.. the reason is because you can in fact have anything in a the button... for example a couple of images, a video, or even, well, another button!

image

Not sure why you would want to do that, but it is good to know you can!

let's leave the Xaml to look like this:

         <Button x:Name="btnOne" Width="100" Height="50" 
                Content="Push Me!"
                Click="Button_Click">
        </Button>

 

OK, enough playing around.. this is Silverlight 2, it is all about .NET code, so let's show a little of that.   Let's add a simple event handler and write some code. 

Notice how VS makes it so easy to add an event handler

image

And VS also makes it very easy for me to navigate to that event handler

image

 

In the event handler, notice I get strongly typed access to the button I just defined in Xaml.  I can also set a break point..

image

Now, hit F5 and run the solution.. notice what is happening:  the code you just typed is being compiled into a .dll, that dll is being zip'ed up in the .XAP file for deployment with any of its dependences.  It is being copied up to the server project, the ASP.NET page is being loaded, it loads the silverlight player in the browser which downloads .XAP file unzips it loads the Xaml and executes our C# code!

That is a lot for a little button!

image

Notice how clicking on it changes the next and hits our break point!  All the power of VS right here in your Silverlight application.

image

Ok, that is cool, but how about some of that richness...  Let's talk a little bit about the developer\designer collaboration in VS\Expression. 

Notice on my Xaml file, I can right click and Open in Expression Blend

image

This is where we move into design mode and actually build some cool UI...

In Blend, select the Layout Root and give it a nice gradient fill. 

image

(you can tell I am not really a designer...)

Now, let's do a little animation, to do that, add a new Story Board

image

Now simply change any properties of the button, move it around the screen to define the animations you want to happen and the different times

image

 

Save the changes, and why you pop back to VS, it tells you the Xaml has been changed... This is way better than passing bitmaps around between developers and designers.

image

Then we go back into our click event and start that story board

 

 private void Button_Click(object sender, RoutedEventArgs e)
{
    btnOne.Content = "I've been pushed!";
    Storyboard1.Begin();
}

For a fun little Silverlight version of the moving button game, add an event handler for mouse enter and play the story board from there

       <Button x:Name="btnOne" Width="100" Height="50" 
                Content="Push Me!"
                Click="Button_Click"
                MouseEnter="btnOne_MouseEnter"
                RenderTransformOrigin="0.5,0.5">

 

 private void btnOne_MouseEnter(object sender, MouseEventArgs e)
{
    Storyboard1.Begin();
}

 

Ok... that was fun, but let's go back into Blend now and define a little more sensible UI..

Notice the snap lines and layout help?

image

And how easy it is to define a grid layout and get docking and resize to work correctly

image

 

Now to work around a little bug in Expression, we need to add a reference to the System.Windows.Controls.Data.dll assembly where the DataGrid control lives.   You do that under Project\Add Reference.  It should be in the "C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client" directory.

image

 

Now from the asset library it is easy to find DataGrid

image

image

 

 

III.  Defining the Data Layer

Ok, that is all fun UI stuff, but now let's get down to it.   Let's go back to the server project and add a data layer. 

First, just to get access to the database, I add northwind.mdf to the app_data director

 

Then, right click, add new item and select Ling to Sql Classes.  Notice that EF or NHibranate or whatever would work in the same way.

image

 

Then, in the Linq designer add the Products table from Northwind

image

Now, we need to make sure that the Linq model is created in a way that we can expose it over a web service.  So I need to change the Serialization Mode to Unidirectional

image

Clearly if this were more real world, at this point I would add data validation and business logic. 

 

 

IV. Define the Services Layer

I'll show creating a services layer with WCF. 

Right click, add new Item and select WCF Service

image

 

Open the services interface and define the right contract

 [ServiceContract]
public interface INorthwindService
{
    [OperationContract]
    List<Product> GetProducts(string productNamePrefix);
}

 

Then open the concrete implementing and click on the smart tag on the interface and implement the interface

image

This creates the following code

 public class NorthwindService : INorthwindService
{
    public List<Product> GetProducts(string productNamePrefix)
    {
        throw new NotImplementedException();
    }

}

Now I need to create the implementation  of this method which is simple with Linq.

 public List<Product> GetProducts(string productNamePrefix)
{
    NorthWindDataContext db = new NorthWindDataContext();
    var q = from p in db.Products
            where p.ProductName.StartsWith(productNamePrefix)
            select p;
    return q.List();
}
  

The final step here is to change the WCF binding to httpBasic as that is what the current Silverlight client supports. In web.config change wsHttpBinding to basicHttpBinding

image

The new web.config changes are:

 <endpoint address="" binding="basicHttpBinding" 

 

IV. Consume the Service in the Silverlight client

Now we need to consume the service from the Silverlight client. 

The first step is to add Service reference to the client project

image

 

Click "Discover"

image

 

Now, let's make sure our Textbox and DataGrid are accessible from C# code by setting their x:Name and while we are there, let's set the AutoGenerateColumns on DataGrid to true. 

image

 

Now, in the code behind for page.xaml, do three things:

1. Create the NorthwindServiceClient class that is the holder for the service calls
2. All network call in Silverlight are aync to keep the browser from hanging, so we need to setup a callback, notice that VS does a lot of this for you.
3. Make the async call. 

 private void Button_Click(object sender, RoutedEventArgs e)
{
    var client = new NorthwindServiceClient();
    client.GetProductsCompleted += 
        new EventHandler<GetProductsCompletedEventArgs>(client_GetProductsCompleted);
    client.GetProductsAsync(txtProductString.Text);
}

 

Then the completed callback is simple!  just set the datagrid's ItemSource to the events Results

 void client_GetProductsCompleted(object sender, GetProductsCompletedEventArgs e)
{
    dataGridResults.ItemsSource = e.Result;
}

Run it, enter some prefix hit submit and see the results!  Yea!

image

 

Ok, that is cool, but let's see if we can leverage some of the local storage capability of Silverlight.  For example, let's cache the result so that whenever the application is loaded we show the results of the last call with no network hit.

To do this, in page.xaml.cs add an import for IsolatedStorage

 using System.IO.IsolatedStorage;
  

Create the settings instances in the page class

 public partial class Page : UserControl
{
    ApplicationSettings settings = ApplicationSettings.Default;

 

then simply save the results in the property store

 void client_GetProductsCompleted(object sender, GetProductsCompletedEventArgs e)
{
    dataGridResults.ItemsSource = e.Result;
    settings["defaultDataGridValue"] = e.Result;
    settings.Save();
}

and reload them, if they are there on the page load.

 public Page()
{            
    InitializeComponent();
    if (!settings.Contains("defaultDataGridValue"))
    {
        settings.Add("defaultDataGridValue", null);
    }
    else
    {
        dataGridResults.ItemsSource = settings["defaultDataGridValue"] as Product[];
    }
}

Now notice the first time you run it, nothing is in the datagrid.  But do you search, the result display, then close the browser and re-run... the last search results will be displayed.  Now open it in FireFox, again the results are there.

 

 

V. Sex up the UI a bit

Now, let's see if you can make the UI even cooler.  Let's do that by skinning all the controls.  Corrina has created some great skins, let's see about applying one.

To do that, grab the Application.Resources section out of app.xaml file in corrina's Rough sample and copy it this applications app.xaml file.  You'll also need to add the data namespace to app.xaml

 xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

 

Then, we need to reference these styles from the page.xaml.

         <Button Style="{StaticResource buttonStyle}"

         <TextBox Style="{StaticResource textBoxStyle}" 
         <System_Windows_Controls:DataGrid Style="{StaticResource dataGridStyle}"

 

Then you run it and it looks great!

image

 

Download the completed sample

I'd love to hear your feedback\thoughts.