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
- Explain the Silverlight Project Format
- How to do rich layout and animation
- Uses line of business controls for Silverlight such as DataGrid
- Has a Linq based data layer on the server on the server
- Exposes business logic over that data via a WCF web service
- Consume the service on the client in Silverlight and databind to the DataGrid
- Store result locally to minimize round trips to the server across instantiations with IsolatedStorage
- Re-theme the UI to make it look more cool.
- Do it all in code that you could easily write on stage in about 30-45 mins
- 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..
I. Create the Silverlight Project
In VS2008 with the Silverlight 2 Tools for Silverlight installed, create a new Silverlight application
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:
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.
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.
Now, that button defaults to filling the entire grid, so let's give it a size, and some text...
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!
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
And VS also makes it very easy for me to navigate to that event handler
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..
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!
Notice how clicking on it changes the next and hits our break point! All the power of VS right here in your Silverlight application.
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
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.
(you can tell I am not really a designer...)
Now, let's do a little animation, to do that, add a new Story Board
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
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.
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?
And how easy it is to define a grid layout and get docking and resize to work correctly
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.
Now from the asset library it is easy to find DataGrid
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.
Then, in the Linq designer add the Products table from Northwind
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
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
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
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
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
Click "Discover"
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.
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(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!
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!
Download the completed sample
I'd love to hear your feedback\thoughts.