It seems carousels are in vogue in the RIA world. First I saw a Flash-based carousel on Amazon. Then came Tafiti, and the main silverlight.net site followed by displaying a carousel of search results and video streams. So I figured why not use a carousel within a photo viewer application to demonstrate Script# as the way to build JavaScript-based Silverlight 1.0 applications in C#. Silverlight 1.1 will of course bring CLR execution, but in the meantime you can still benefit from an improved developer and tools experience that comes with C#. The Script# compiler then takes care of compiling that code down to regular Javascript code. This post will also give me some context to introduce some interesting features of the Script# framework.
I will build a reusable, data-bound templated carousel control, modeled very similar to the Repeater control from ASP.NET. Once I have this carousel control, I'll bind it to a list of... yes, you guessed it... photos returned from calling the Flickr API. Here is a screen shot of the end result, so you have something to look forward to and stay tuned as well as visualize what is being built as I post the individual parts.

I used Visual Studio 2005, along with Script# v0.4.2.0. The 0.4 set of builds have been released in the past couple of weeks to sync up with Silverlight 1.0, along with feature additions and bug fixes that should come in handy. In general, I would recommend tracking the release history, and getting the latest build off of the script# project page. I've talked to various companies who have successfully started using Script# for their Silverlight work. If you're using it drop me a note.
In part 1, I wanted to do something simple so I can focus on the integration of Script# with Silverlight. I'll build a super-simple photo control that displays a thumbnail, and has some mouse hover interaction behavior. This can then later be adapted into the overall more interesting scenario, as the item template handed to the carousel control. Specifically this will show getting started on using C# to create Silverlight controls, and work against the XAML DOM, as well as compiling the C# code into script that can then be incorporated into an HTML page.
I'll be posting the full series over the course of this week and next, giving folks a chance to read through one part at a time. Hopefully this will be interesting and provide a mental model for applying Script# to doing RIA development with Silverlight 1.0. A number of concepts I present here can be used in the context of regular DHTML-based Ajax client apps as well.
Step 1: Create a new Script# enabled web site.
There are some one-time setup tasks before we can get going. The first is to create a site. I'll create a script#-enabled web site, which is a regular web site, with the addition of the core Script# framework (the script files such as sscorlib.js in the App_Scripts folder) as well as the equivalent C# assemblies (the .dll files such as sscorlib.dll in the bin\Script folder). The scripts are used at runtime in the browser, and the assemblies are used at compile-time.

I created the site in C:\SilverlightApp\Site. You can choose whatever you want, but remember the path, as that will be interesting in the next step.
Step 2: Add a C# Class Library Project
We're going to implement the photo viewer in a class library. When this class library is compiled with the Script# compiler, it will result in debug and release scripts, which we'll consume within the site.
Add a new project in the solution. Specifically I will choose the "Class Library in a Web Site" template.

The special thing about this template is that it assumes the project folder is placed within the bin\Script folder of a site, and places the resulting dll into the bin\Script folder, and the resulting script files into the App_Scripts folder of the containing site. So accordingly, I have chosen to place the project in C:\SilverlightApp\bin\Script. The nice side-effect of this approach is that the script files end up in a browsable location, and the C# code and assembly end up being non-browsable.
Note that if you need to create a component outside the context of a web site, you can simply choose the regular Class Library project template.
Step 3: Create some UI in XAML
This is usually the starting point for anything Silverlight related, and its no different here. I opened up Expression, and created some simple XAML to represent a photo image surrounded by a photo frame contained within a container canvas. This is what I ended up with saved as Photo.xaml within the web site.
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Background="White">
<Canvas x:Name="photoContainer" Width="93" Height="93" Canvas.Left="33" Canvas.Top="34">
<Rectangle x:Name="photoShadow"
RadiusX="3" RadiusY="3" Width="93" Height="93" Fill="Black" Opacity="0.25"/>
<Rectangle x:Name="photoFrame" Fill="White"
Canvas.Left="5" Canvas.Top="5" Width="83" Height="83" Stroke="#FF808080" />
<Image x:Name="photoImage" Width="75" Height="75" Canvas.Left="9" Canvas.Top="9"
IsHitTestVisible="false" />
<Image x:Name="photoSelector" Width="16" Height="16" Canvas.Left="65" Canvas.Top="65"
Source="Camera.png" Opacity="0" IsHitTestVisible="false" />
</Canvas>
</Canvas>
Nothing earth-shattering, but simple is good initially.
Step 4: Creating a Photo control
We want to start associating some code with this bit of XAML, so we can do things like set the image source dynamically. In this step I'll create a simple photo control that will encapsulate the photo image, provide a PhotoUri property, and will manage user interaction within the photo.
In the PhotoViewer class library project add a reference to ssagctrl.dll. This is the Script# assembly containing metadata representing the scriptable Silverlight APIs.

Remove the existing Class1.cs from the class library project, and go ahead and add a new class called PhotoControl.

In this class, add the following two import statements.
using System.Silverlight;
using System.Silverlight.Presentation;
The Silverlight namespace contains APIs representing the Silverlight plugin, and the Presentation subnamespace contains the core XAML UI objects. Script# factors the Silverlight APIs into logical namespaces as opposed to being a flat API. There are a few other namespaces as well. Just open ssagctrl.dll in .net reflector to get a full sense of the APIs.
Here is the code for the class:
public sealed class PhotoControl : IDisposable {
private Canvas _containerCanvas;
private Canvas _frameCanvas;
private Image _image;
public PhotoControl(Canvas rootCanvas) {
// Find the interesting XAML elements we want to program against
_containerCanvas = (Canvas)rootCanvas.FindName("photo");
_frameCanvas = (Canvas)_containerCanvas.FindName("photoFrame");
_image = (Image)_containerCanvas.FindName("photoImage");
// Center the photo within the silverlight control
SilverlightControl control = rootCanvas.GetHost();
Canvas.SetLeft(_containerCanvas, (control.Content.ActualWidth - _containerCanvas.Width) / 2);
Canvas.SetTop(_containerCanvas, (control.Content.ActualHeight - _containerCanvas.Height) / 2);
}
public string PhotoUri {
get { return _image.Source; }
set { _image.Source = value; }
}
public void Dispose() {
if (_containerCanvas != null) {
_image = null;
_frameCanvas = null;
_containerCanvas = null;
}
}
}
The pattern I chose is one where the constructor is provided a root canvas object, and it then proceeds to find various interesting nested elements using FindName. It exposes a PhotoUri property which it maps to the Source of the contained Image element. Finally, it implements IDisposable. This allows it to package its cleanup code in one spot. Of course someone needs to call Dispose, and we'll see that happening in a bit.
Some other things to note. Notice the calls to Canvas.SetLeft and Canvas.SetTop used to set the Canvas.Left and Canvas.Top values of the _containerCanvas element. These are strongly-typed APIs representing attached properties in Silverlight; In fact, Script# provides a strongly typed API for all XAML DOM programmatic access. This drives greater discoverability of APIs, enables intellisense (as shown in the screen-shot below), ability to perform compile time checking etc. Indespensible goodness (at least that is my opinion).

If you're interested in looking at the generated Javascript, simply compile the project, and see the generated PhotoViewer.debug.js and PhotoViewer.release.js files. The latter is a minimized equivalent of the former.
Step 5: Adding interactivity to the control
So far we only have a static image, which isn't terribly interesting. Lets add some simple interactivity such as a mouse hover behavior activated by mouse enter and leave events. Rather than defining the specific behavior in code, the effect is largely defined as a set of animations or storyboards in XAML, so they can be designed within Expression. The code simply triggers these declarative storyboards at the right points.
So in XAML, for example, here is the storyboard to play when the photo is activated.
<Storyboard x:Name="photoActivateStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="photoShadow" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:0.25" Value="0.1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="photoSelector" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:0.25" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="photoScale" Storyboard.TargetProperty="ScaleX">
<SplineDoubleKeyFrame KeyTime="0:0:0.25" Value="1.25"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="photoScale" Storyboard.TargetProperty="ScaleY">
<SplineDoubleKeyFrame KeyTime="0:0:0.25" Value="1.25"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Basically this tweaks the opacity of the shadow to make it lighter, and scales the photo a bit, giving the illusion of the photo being raised in z-order. There is a corresponding photoDeactivateStoryboard defined in the XAML to revert things back to their normal state. As you can see, using storyboards helps keep the designy aspects closer to the designer by specifying them declaratively in XAML. Back in the code, the PhotoControl class is updated with the following additions to start listening to mouse enter and leave events, so it can trigger the storyboards.
public sealed class PhotoControl : IDisposable {
private Storyboard _activateStoryboard;
private Storyboard _deactivateStoryboard;
private object _mouseEnterCookie;
private object _mouseLeaveCookie;
public PhotoControl(Canvas rootCanvas) {
_activateStoryboard = (Storyboard)_containerCanvas.FindName("photoActivateStoryboard");
_deactivateStoryboard = (Storyboard)_containerCanvas.FindName("photoDeactivateStoryboard");
_mouseEnterCookie = _frameCanvas.AddEventListener(InputEvent.MouseEnter, new EventHandler(OnMouseEnter));
_mouseLeaveCookie = _frameCanvas.AddEventListener(InputEvent.MouseLeave, new EventHandler(OnMouseLeave));
}
public void Dispose() {
if (_containerCanvas != null) {
_frameCanvas.RemoveEventListener(InputEvent.MouseEnter, _mouseEnterCookie);
_frameCanvas.RemoveEventListener(InputEvent.MouseLeave, _mouseLeaveCookie);
}
}
private void OnMouseEnter(object sender, EventArgs e) {
_activateStoryboard.Begin();
}
private void OnMouseLeave(object sender, EventArgs e) {
_deactivateStoryboard.Begin();
}
}
The key things to notice are the calls to AddEventListener and the corresponding RemoveEventListener in the dispose logic. In the event handler trigger the storyboards in response to the user's actions. One other side thing to notice is the use of enumerations in the event type, as opposed to string names. This is again in an effort to increase strong typing. However this developer benefit doesn't come with a runtime cost. Script# is able to simply generate a string name at runtime, and in general, the generated script code works against the native scriptable API, rather than some abstraction or wrapper.
Step 6: Creating the Silverlight Control
We're now ready to use the PhotoControl on a page. To do so, we're going to write a scriptlet. A scriptlet is essentially a Script# approach for defining a main method in a Web page. Just like a main method in a client app creates and instantiates the main window, the Scriptlet is going to create the Silverlight plugin instance and add it to the HTML page.
Add a class, and choose the scriptlet template item. Name the class PhotoScriptlet.

public class PhotoScriptlet {
public static void Main(Dictionary arguments) {
// Specify source, container HTML element and ID to create the Silverlight control
// ControlParameters contains other optional settings as well
ControlParameters controlParameters =
new ControlParameters((string)arguments["xaml"],
(DOMElement)arguments["xamlContainer"],
"photoViewer", null);
controlParameters.windowless = true;
ControlFactory.CreateSilverlight(controlParameters, OnLoaded, null, arguments);
}
private static void OnLoaded(SilverlightControl control, object context) {
PhotoControl photoControl = new PhotoControl((Canvas)control.Content.Root);
Application.Current.RegisterDisposableObject(photoControl);
Dictionary arguments = (Dictionary)context;
photoControl.PhotoUri = (string)arguments["photo"];
}
}
The main method essentially creates a Silverlight control using the specified XAML file, at the specified location in the HTML tree. There are a number of options on the ControlParameters class that I'd recommend checking out. The OnLoaded method is called when the XAML has been loaded, and ready to be programmed. The OnLoaded implementation instantiates our PhotoControl instance.
Earlier, I mentioned that PhotoControl implements IDisposable to encapsulate its cleanup code. The PhotoControl instance is registered as a disposable object with the global Application object (provided by the Script# framework). This manages a list of IDisposable object, and takes care of disposing our control at page unload time.
The last step is to reference the resulting Javascript from the page. This can obviously be done manually using script tags, but the scriptlet server control simplifies this. It also generates code to load script files dynamically, and call the main method once scripts have been loaded.
<div id="photoViewerContainer" s/>
<ssfx:Scriptlet runat="server" ID="scriptlet" PrecompiledScriptlet="PhotoViewer.PhotoScriptlet">
<References>
<ssfx:AssemblyReference Name="sscorlib" />
<ssfx:AssemblyReference Name="ssagctrl" />
<ssfx:AssemblyReference Name="ssfx.Core" />
<ssfx:AssemblyReference Name="ssfx.UI.Forms" />
<ssfx:AssemblyReference Name="PhotoViewer" />
</References>
<Arguments>
<ssfx:StringLiteral Name="xaml" Value="Photo.xaml" />
<ssfx:ElementReference Name="xamlContainer" ElementID="photoViewerContainer" />
<ssfx:StringLiteral Name="photo" Value="SamplePhoto.jpg" />
</Arguments>
</ssfx:Scriptlet>
You'll notice the arguments collection being used in the scriptlet code. This argument collection is built from the set of arguments defined on the Scriptlet server control. This allows externalizing values and avoid hardcoding page specific values within the class library. The second collection on a Scriptlet is a list of assembly references - each assembly maps to the corresponding .js file. The Scriptlet generates a script reference to include the bootstrapping script as a <script> tag, and then loads the rest of the referenced scripts dynamically.
To recap, the first past demonstrated using Script# to develop a basic UI using interactive XAML elements on the page. Script# allows you to work in C# using Silverlight 1.0 today. Here are the screenshots of what we ended up with (in both normal state, and mouse activated state):
You can download the sample code for part 1, to follow through and run the sample on your end.
.
In case you're wondering, you don't have to buy in into the Scriptlet model for linking script code into the page. The key message was around C#-based authoring and compiling to script. How you choose to consume the generated script code in your site is really up to you. I chose to use a scriptlet here, since I like the main entrypoint method concept that exists in client apps being applied to RIA and Ajax apps.
In subsequent posts in this series, I'll be building up the carousel control, and then adding data-binding and templating as well as query Flickr to get a list of actual photos.