Spelunking the DOM with Silverlight 1.1 - Part 1
Rod Paddock - Visual Basic MVP, Dash Point Software, Inc.
Download the code
September 2007
Silverlight 101 and DOM Integration
I was lucky enough to attend the MIX 07 conference this year in Las Vegas, NV. The big news from MIX was the release the Silverlight Alpha 1.1 platform. Silverlight is a browser plug in that gives developers the ability to create XAML based user interfaces that can run in Windows, Macintosh and, according to Scott Guthrie, Linux browsers in the near future. As soon as I got back from MIX I dove into building Silverlight applications using Visual Studio 2008, VB.NET, and the Silverlight SDK.
Why Silverlight?
Let's begin this article by discussing the reasons why developers would want to build web applications using Silverlight 1.1.
- Reach
- CLR Code
- CLR Tools
- JavaScript sucks
The first reason is Reach. The web is all about eyeballs. With some basic HTML and a couple of clicks, your web application is accessible to literally millions of people. Silverlight 1.1 gives developers the ability to create .NET-based applications that are immediately accessible to millions of potential users.
Next we move onto the CLR. With Silverlight you can run CLR code in a sandboxed browser plug-in. You can run CLR code on a Macintosh; you can use the Visual Studio Debugger on your Silverlight web applications (including the MAC!). It's CLR everywhere. CLR CLR! CLR!! CLR!!! Need I say more?
Finally, I don't know about you, but writing and debugging JavaScript is a pain. Silverlight 1.1 has great mechanisms for accessing the DOM of your browser and manipulating its contents. If I can attach CLR code to my browser DOM, why would I ever write JavaScript?
So, with that in mind, let's get to work creating some Silverlight Applications.
Architecture
The architecture of our sample application is very simple. This application will be a standard three-tier application:
User Interface: Built using HTML and Silverlight, communicates with Web service Over HTTP
Web Service: Built using VB.NET and will access SQL Server data via System.Data.SQLClient
SQL Server: Simple customer table. Accessed via dynamic T-SQL (SELECT and INSERT)
This article will follow the 80/20 principle. It will focus on the 20% of the stuff you do 80% of the time. Normal applications take data from databases and put it on the screen. They then have facilities to add data to the database. This article will focus on these items.
Silverlight 1.0 or Silverlight 1.1?
This article will focus on building Silverlight 1.1 applications. Silverlight 1.0 is a WPF/JavaScript-based platform for building rich web user interfaces. Silverlight 1.1 is a more powerful version that allows you to integrate CLR code into your web applications.
Requirements
Before you can build your first Silverlight 1.1 application, you will need to download and install the following applications:
Please go to http://www.silverlight.net/GetStarted for more information on installation options and designer tools.
Creating the Basic Silverlight Application
After downloading and installing all of the Silverlight 1.1 prerequisites, you can go to work creating your first Silverlight application. For this part of the application, you are going to use Visual Studio 2008 to create an empty solution, and then add a Silverlight 1.1 application to that solution.
Creating the Solution
The first item to create is a new empty solution. First make sure that Visual Studio is displaying solutions in the Solution Explorer by going to Tools > Options, and then, under Projects and Solutions, select "Always show solution". To create your new solution, do the following:
- Open Visual Studio 2008.
- Select File > New Project from the Visual Studio menu.
- From the New Project dialog box, choose Other Project Types > Visual Studio Solutions > Blank Solution.
- Choose your folder and name your solution "SpelunkingSilverlight". Your New Project dialog box should now look like Figure 1.
.png)
Figure 1. Creating a new empty solution.
Creating Your Silverlight Project
The next step is to add a new Silverlight 1.1 project to your solution. When you installed the Silverlight 1.1 SDK, a number of new templates were installed into your Visual Studio shell. To create your new Silverlight project, do the following:
- Right-click your solution and select Add > New Project from the popup menu.
- From the New Project dialog box, choose Visual Basic > Silverlight > Silverlight Project.
- Choose your folder and name your solution "SpelunkingSilverlightUI". Your New Project dialog box should look like Figure 2.
.png)
Figure 2. Creating a new Silverlight 1.1 project
Spelunking the UI Project
Newly created Silverlight applications have the following files automatically created:
TestPage.html: This is a standard web page that contains the JavaScript code to load the Silverlight plug-in.
TestPage.html.js: This is a JavaScript file that loads your XAML page into the plug-in.
Page.xaml: This is the default WPF/XAML page for your user interface, and it will be loaded into the plug-in on TestPage.html.
Silverlight.js: This is a small JavaScript file that controls the instantiation of the Silverlight plug-in.
Silverlight UI XAML vs. DOM
My first forays into creating Silverlight applications focused on the concept of creating a simple user interface. Like that of most developers, my goal was to create a simple form with a button or two and add some simple code to those buttons to make something happen. You know the application: "Hello World, Silverlight Edition". This is where I ran into a roadblock. The WPF library included with Silverlight is rather primitive and lacks a robust set of controls, includingbelieve it or not buttons. So, faced with this quandary, what is a developer/hacker to do? I had a number of choices:
- Create my own WPF style button from the available WPF primitives.
- Use a simple set of controls provided in the Silverlight 1.1 SDK .
- Integrate with HTML controls provided via the browser DOM.
Option 1 had some appeal to my inner hacker, but ultimately I didn't have the time to spend implementing my own button. Option 2 was suitable, but I really wanted a full set of controls to provide my UI. So I chose the path that gave me the most bang for the buck. I decided that I would integrate my web page into the existing HTML DOM, conveniently provided by my browser. This path provided me with a rich set of controls with little or no effort required to integrate them into my application.
My preference would have been to the use the more elegant programming model of XAML and WPF controls. But at this stage it's just not possible. I am sure (like the sky is blue) that the next iteration of Silverlight 1.1 will have a richer set of controls. We'll revisit this sample again when that happens. And as a side note, I could have just as easily integrated this into a web form, but I wanted all of the user interface code to reside in the client and have no server interaction involved.
Browser DOM Concepts
This small application will demonstrate the following concepts centered on maintaining a list of customers:
- integrating the Silverlight plug-in with the browser DOM
- attaching events to HTML DOM controls
- reading properties from HTML DOM controls
- setting properties on HTML DOM controls
- creating new HTML DOM Controls
Creating the Basic Web Page
After creating your Silverlight project, you can go to work creating your basic HTML page. This example will change the content found in the TestPage.HTML file. You will be adding the following controls/tags:
- a <table> tag to control the UI's layout
- a <button> tag to add interactivity to the UI
- an <input> tag for a user to key in the name of a customer
- a <select> control to contain a list of customers
Before you modify your HTML page, you need to make one change to the default page.xaml file. Change the default Width and Height properties of the Panel object. By default, this Panel control is set to 640 by 480 pixels. Change these values to 0 and 0 respectively. If you do not change the dimensions of your plug-in, your HTML controls will show up at the bottom of your page. Your XAML code should look like:
<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="SpelunkingSilverlightUI.Page;assembly=ClientBin/SpelunkingSilverlightUI.dll"
Width="0"
Height="0"
Background="White"
>
</Canvas>
Now you can move back to the modification of your HTML page. For brevity's sake, your HTML code will be as follows:
<head>
<title>Silverlight Project Test Page </title>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="TestPage.html.js"></script>
<style type="text/css">
.silverlightHost { width: 0px; height: 0px; }
</style>
</head>
<body>
<div id="SilverlightControlHost" class="silverlightHost" >
<script type="text/javascript">
createSilverlight();
</script>
</div>
<form>
<table>
<tr>
<td><button type="button" id="cmdAddCustomer">Add Customer To List</button></td>
<td><input id="txtCustomerInput" type="text" value="Put Customer Name Here..." /></td>
<td><input id="txtCustomerOutput" type="text" value="..." /></td>
<td><select id="cboCustomerList"></select></td>
</tr>
</table>
</form>
</body>
</html>
NOTE: You will also need to change the CSS code found in the TestPage.html file. Look for the following line:
.silverlightHost { width: 640px; height: 480px; }
And change it to
.silverlightHost { width: 0px; height: 0px; }
This is a CSS stylesheet tag that will change the size of your Silverlight control.
Your HTML page will now look like Figure 3:
.png)
Figure 3. Creating the User Interface
Integrating with the Browser DOM
Once you have created the HTML for your basic web page, you need to bridge the Silverlight plug-in and your browser page. To create your Silverlight DOM bridge, do the following:
- Open the Page.xaml.vb file (right-click Page.XAML and select View Code).
- Import the browser namespace:
Imports System.Windows.Browser
- Add a member variable to the page:
Dim oDocument As System.Windows.Browser.HtmlDocument
- In the New() method of the page, attach the browser DOM to your member variable:
Me.oDocument = HTMLPage.Document
That's it for that step. Now your Silverlight application can access controls on your browser page.
Attaching Events
Now it's time to make your controls do something. In this part, you will add an event handler to your browser button. The first step is to create the subroutine that will handle your button's click event. The following code demonstrates a basic button event handler:
Sub cmdAddCustomerButtonHandler _
(ByVal o As Object, ByVal e As HtmlEventArgs)
End Sub
Now that you have created the basic structure for your handler, you can attach an event to your button. Attaching events in Silverlight is a two-step process. The first step is to retrieve a handle to your control using the DOM Document's GetElementByID function. Then you call the control's AttachEvent method. The following code attaches the click event of the cmdAddCustomer button to your event handler:
'-- add button handler code
Dim oButton As HtmlElement = _
Me.oDocument.GetElementByID("cmdAddCustomer")
oButton.AttachEvent("onclick", AddressOf Me.cmdAddCustomerButtonHandler)
Note: Adding event handlers to XAML-based controls is much simpler. Event handlers can be added using normal Visual Studio IDE operations, such as selecting the event from the property window or drop downs in the Visual Studio code window.
Silverlight DOM Weirdness
This is where it gets a little strange. If you put a breakpoint on the GetElementByID line and step over it, you will notice that the value of oButton is Nothing. For some reason, the DOM document doesn't load properly when accessing the web page via a Windows drive (e.g., "c:\my documents\blah\blah"). So how do you fix this issue? The solution is to create a "real" web site to run this application. Use the following steps to create your "real" web site:
- Right-click the current solution and select Add > New Project from the pop-up menu.
- From the New Project dialog box, choose Visual Basic > Web > ASP.NET Web Application.
- Choose your folder and name your solution "SpelunkingSilverlightDomTester". Your New Project dialog box should look like Figure 4.
.png)
Figure 4. Add a new web application for testing the UI project.
- Drag and drop the following files from your SpelunkingSilverlightUI project into your SpelunkDomTester project:
- TestPage.html
- TestPage.html.js
- Silverlight.js
- Right-click the SpelunkDomTester project and select "Set as Startup Project".
- Right-click TestPage.HTML on the SpelunkDomTester project and select "Set as Start Page".
- Right-click the SpelunkDomTester project and select "Add Silverlight Link".
- From the provided dialog box, select the SpelinkingSilverlightUI project.
- Answer in the affirmative when asked about debugging Silverlight applications.
- Run your app by pressing F5.
- You should now see an HTMLElement object returned from the GetElementByID function.
Coding the Event Handler
After attaching your event handler you can now go to work and make that handler actually do something.
Manipulating the HTML Page
The following code will change the background color of your HTML form:
Me.oDocument.SetProperty("bgcolor", "cyan")
Setting Control Properties
The next technique to explore is setting a property on a control. Setting control properties follows a pattern similar to adding event handlers. First, retrieve a reference to the control and then set a property on the control using the SetProperty method. The following code will retrieve a handle to the txtCustomerOutput text field and then set the Value attribute to the current time.
Dim oOutput As HtmlElement = Me.oDocument.GetElementByID("txtCustomerOutput")
oOutput.SetProperty("Value", Now.ToString)
Retrieving and Setting Control Properties
The next technique demonstrates reading a property from a control. This example will retrieve a handle to the cmdCustomerInput control, retrieve the Value property and set an uppercase version of that value on the cmdCustomerOutput control.
Dim oInput As HtmlElement = Me.oDocument.GetElementByID("txtCustomerInput")
Dim cValue As String = oInput.GetProperty(Of String)("Value")
oOutput.SetProperty("Value", cValue.ToUpper)
Note: The GetProperty method uses generics to control the return casting of the property. The giveaway is the use of the "of" keyword.
Creating New DOM Objects
This final example will demonstrate creating new DOM objects and adding them to your page. The code will take the data entered in the txtCustomerInput control and add it to the <select> tag's <options> collection. Adding a new object follows this pattern:
- Create a handle to the object to which you want to add content.
- Create a new element with the DOM's CreateElement method.
- Set property/attributes on the newly created element.
- Add the newly created object to the parent object using the AppendChild method.
The following code takes the contents specified in the txtCustomerInput contol and adds it to the <select> object's <options> collection.
Dim oInput As HtmlElement = Me.oDocument.GetElementByID("txtCustomerInput")
Dim cValue As String = oInput.GetProperty(Of String)("Value")
Dim oSelectObject As HtmlElement =
oDocument.GetElementByID("cboCustomerList")
Dim oNewOption As HtmlElement = Me.oDocument.CreateElement("option")
oNewOption.SetAttribute("innerHTML", cValue)
oNewOption.ID = System.Guid.NewGuid.ToString
oSelectObject.AppendChild(oNewOption)
Your final output should look like Figure 5:
.jpg)
Figure 5. Final HTML page for Spelunking Silverlight Part 1
Conclusion
At this point you have built a nice hybrid HTML and Silverlight application. As I like to say, "Doesn't cost much, doesn't do much." In the next edition we will integrate this application with a Web Service. You .NET developers may be saying, "pshaw, that's easy." Well, this is Silverlight Alpha 1.1 and what should be simple is not so simple. Stay tuned. (Editors Note: Read Spelunking the DOM with Silverlight 1.1 - Part 2: Integrating Web Services)
About Rod Paddock
Rod is a Microsoft MVP and owner of Dash Point Software, Inc. and co-owner of Red Matrix Technologies. Rod is a long-time software developer helping companies implement software-based solutions. Rod has worked for such companies as First Premier Bank, Six Flags, Microsoft, Intel, System Improvements, and many others. Rod has been a featured speaker at a number of conferences in the US, Canada, and Europe. Rod is a member of both the INETA and MSDN Canada speaker bureaus. Rod is also editor in chief of CoDe Magazine. Rod's blog is found at http://blog.dashpoint.com. Rod's web site is http://www.dashpoint.com.