Wednesday, June 06, 2007 -
This is going to be one of those "silly" examples, but I hope it illuminates the Silverlight landscape a little. In this post I'll work up an ASP.NET website, create a Silverlight control, and feed it some data from SQL Server.
Prerequisites
I'm using Silverlight 1.1 Alpha. To play along you'll need to install the goodies from here, which are:
One thing I'd like to point out here is that Orcas is silly fast. It's wonderful to have the IDE back :).
Step 1: Create the Web site
Simple stuff really, we all know how to do this. Open up Orcas and go to File >> New Website. Pick your favorite language - mines C# so I'll choose that.
Step 2: Create a Silverlight project. Same deal here - just go to File/New Project, select your language, and then Silverlight. From this menu choose "Silverlight Application":
Step 3: Add in a folder to hold client-side script to your web application. I like to call mine "js" by habit - call yours what you like. In it, add a file called "CreateSilverlight.js", and leave it blank for now.
Step 4: Drag the "Silverlight.js" file into your web app's js folder, and the "Page.xaml" file into the web's root- we're not going to use this project for this example - instead (to illustrate a little more how the players play together) we're going to put the pieces together in one place.
Step 5: Create an aspx web page that doesn't have a code-behind, and no master page. Call it XAMLPage.aspx for now. When finished, your project should look something like this:
Step 6: Create some basic XAML for testing. In this example I'm going to create a simple TextBlock that says (what else) "Hello World" and put it into Page.xaml:
<Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="parentCanvas" Width="640" Height="480" > <TextBlock Name="myBlock" Text="Hello World" Width="200" Height="200" FontSize="22" Foreground="#FF000000"/> </Canvas>
What we want to do here is to call Default.aspx, instance a Silverlight control, and then feed that control some data. To do this, we need to utilize some javascript. The Silverlight.js page is a requirement for running any Silverlight apps on a web page, since it has all the goodies in it to detect the client, detect installation, and instance Silverlight. We don't want to change that file at all since it's does it's job well.
The second js file, which is blank, is a jscript file that will create the client and feed it some XAML (this is optional). Let's take a look at the script needed for this page:
// JScript source code //contains calls to silverlight.js, example below loads Page.xaml function createSilverlight() { Sys.Silverlight.createObjectEx({ source: "Page.xaml", parentElement: document.getElementById("SilverlightControlHost"), id: "SilverlightControl", properties: { width: "100%", height: "100%", version: "0.95", enableHtmlAccess: true }, events: {} }); }
This is all the script that's in the file, and it's only one method. If you want to customize anything about the control - here is the place to do it. Two things to notice here is that we're telling the control to load the source "Page.xaml" (we're going to change that in a bit), and that we're looking for the element "SilverlightControlHost", which doesn't exist yet. So let's change that.
Step 7: Code up the ASP page. So to make sure everything's wired properly, I'm going to load up an ASPX page and call the Silverlight functions, which in turn will load my Page.xaml file into the Silverlight control. So pop this code into your default.aspx page.
<%@ Page Language="C#" AutoEventWireup="true"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script type="text/javascript" src="js/Silverlight.js"></script> <script type="text/javascript" src="js/CreateSilverlight.js"></script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Hello Silverlight, So Glad To Meet You!</title> </head> <body> <form id="form1" runat="server"> </form> <div id="SilverlightControlHost" > <script type="text/javascript"> createSilverlight(); </script> </div> </body> </html>
So let's take a look at what's going on here. The page is loading up, and is referencing the two script files located in our script directory. We've also setup a DIV with the id "SilverlightControlHost", and then implanted (for readability) a script call to the "createSilverlight()" method. This method, in turn, instances Silverlight in the browser and then sets the control's XAML source to Page.xaml. Simple enough, and here's what you should see when running the page:
Groovy! Ok everything's working nicely, now let's do something more fun shall we?
Step 8: Make it dynamic. Let's copy the source of our Page.xaml file and put it into an ASPX page - the XAMLPage.aspx that we talked about above. Now that it's in there we can have some fun - like adding some scripting for fun :). Add this source to XAMLPage.aspx:
<%@ Page Language="C#" %> <Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="parentCanvas" Width="640" Height="480" > <%for (int i = 1; i <= 10; i++) { %> <TextBlock Name="myBlock<%=i.ToString() %>" Text="Hello World <%=i.ToString() %>" Width="161.013" Height="62.537" Canvas.Left="-1.013" Canvas.Top="<%=20*i %>" FontSize="22" Foreground="#FF000000"/> <%} %> </Canvas>
Not doing much tricky here - just looping 10 times over the TextBlock declaration, and outputting some info. One thing to note is this bit: Canvas.Top="<%=20 * i %>" this is important since XAML elements will stack, and there is not grid layout or stack panel in Silverlight yet - so you need to be explicit about positioning here. In this case I'm going to stack things 20 pixels apart vertically.
Step 9: Reset the "source". Open up CreateSilverlight.js and reset the source element to "XAMLPage.aspx":
Sys.Silverlight.createObjectEx({
source: "XAMLPage.aspx",
When you run this, you should see:
OK great - the Hello World thing is out of the way - now let's do something a little more worth while, and let's make the scripting a little more usable.
Step 10: Refactor the scripting. We obviously don't want to hardwire these things into our script files - although that is an option if you want to partition each load up of a Silverlight control into it's own script file. In this case I'd like to have one routine load up every Silverlight control on my page. So I'm going to refactor CreateSilverlight.js to allow me to pass in the source and elementid as variables:
// JScript source code //contains calls to silverlight.js, example below loads Page.xaml function createSilverlight(source, elementID) { Sys.Silverlight.createObjectEx({ source: source, parentElement: document.getElementById(elementID), id: "SilverlightControl"+elementID, properties: { width: "100%", height: "100%", version: "0.95", enableHtmlAccess: true }, events: {} }); }
Step 11: Let's do something useful - let's create a menu and a nice welcome message! I created a nice menu control using Expression Blend (more on blend in other writeups) that did you basic jiggety jig when you moused over, and I also created a nice welcome message using some text blocks and the current date. I called the welcome page "XAMLWelcome.aspx" and added this XAML:
<%@ Page Language="C#" %> <Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="parentCanvas" Width="200" Height="35" > <TextBlock Name="welcomeMessage" Text="Welcome back <%=User.Identity.Name%>" Width="161.013" Height="62.537" Canvas.Top="-1" Canvas.Left="-1.013" FontSize="22" Foreground="#FF000000"/> <TextBlock Name="theCurrentDate" Text="<%=DateTime.Now.ToLongDateString() %>" Width="161.013" Height="62.537" Canvas.Top="25" Canvas.Left="-1.013" FontSize="12" Foreground="#FF000000"/> </Canvas>
Next, I added in the menu control. To do this, I had to copy over the Menu XAML file (called Menu.xaml) as well as the dll that the was created as part of my project. I did some code behind to respond to client events (mouse overs and so forth) so this created a dll. To know where to put the DLL, let's take a look at the source of the menu xaml (only the top lines):
<Canvas x:Name="parentCanvas" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="Page_Loaded" x:Class="AGDemo.Menu;assembly=ClientBin/AGDemo.dll" Width="640" Height="480" Background="White" >
Notice the "x:Class" declaration - this tells you where Silverlight's going to look for the dll to fire the menu. So in our web project I need to create a "ClientBin" directory, then add the output dll (AGDemo.dll) to the folder.
The good news here is that you can "link" your web projects to a Silverlight project - see Scott's demo to see more of how that works.
OK, now I have my menu control, and I have my new Welcome control worked up. Let's add them to the page:
<%@ Page Language="C#" AutoEventWireup="true"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script type="text/javascript" src="js/Silverlight.js"></script> <script type="text/javascript" src="js/CreateSilverlight.js"></script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Hello Silverlight, So Glad To Meet You!</title> </head> <body onload="loadAG()"> <form id="form1" runat="server"> </form> <div id="Welcome" style="height:60px"> </div> <div id="Menu" > </div> </body> </html> <script> function loadAG(){ createSilverlight("Menu.xaml","Menu"); createSilverlight("XAMLWelcome.aspx","Welcome"); } </script>
Notice here that I renamed a few things - I created a DIV to hold my welcome message, and then a DIV to hold the menu (such as it is). I then use the onload() event of the body tag to call createSilverlight() for each element I want to load.
Here's the result:
You can't really tell very well, but the menu bounces and moves nicely all over the place :). It's still not very useful, but that's the goal for my next post!
I am worried with how easy they are making it to create such rich content that the number of sites only using technology such as this will increase massively.
Why is this is a bad thing you ask? Can visually impaired / blind users use it? If not you are cutting out a number of potential users from using your site. Plus I think you be breaking a number of disability laws and leaving yourself open to a lawsuit.
Not sure this is actually relevent to this post but I would be interesting in hearing where others see the technology 'fits in'
But seeing the result, I am shocked:
JavaScript dynamically calling ASPX which embeds XAML which embeds C#? (or is it actually the ASPX that embeds the C#?)
Can this be the all-praised, shiny future?
This seems quite an abnormity to me... I am worried, that if this is going mainstream, the schizophrenia-rate among IT-Professionals will rise significantly.
@Thomas: I run it on a desktop and it's very very fast.
Did you miss something?
If you could be more specific with your questions I'll do my best to help you.
Download free eBooks from http://sharpbooks.blogspot.com
Currently I am working with silverlight, and publishing resources and tutorials on silverlight at http:\\www.silverlighttutorials.blogspot.com
This could be useful for silverlight application developers.
Are you still in Redmond?
Last week we were debating about whether UDFs were a "Good" way to go for read-only access operations:
http://www.ayende.com/Blog/archive/2007/06/20/Shocking-Rob.aspx
You offered to ask some of the folks on the SQL server team, and it left some of us hanging. I was interested in hearing their take on UDF usage.
Did you ever get any feedback? I'd love to know.
-pete