There is a simple little feature available in Silverlight that I think everyone should use, or at least more or less everyone. It is the possibility of adding a custom loading screen that will be shown while the plug-in downloads the Xap. It is simple to implement and gives your application that little extra to make it stand out. If you look at Flash for example, you will see that every Flash application has its own loading screen. During the time that the application downloads, you can display how much has been downloaded, but you can also give the user something to look at or even do. My favorite loaders the ones that gives you a simple game to play with while the application loads. This however, is only useful if the application is really big. And in that case, I would recommend splitting up the application in smaller pieces and load them on demand. Anyhow, how do we do it?
Well, it is quite simple. The only thing that might make it “complicated” for some is that it falls back to Silverlight 1.0 features. That is, no C#. It has to be built using only Xaml and JavaScript and cannot include any of the controls.Other than that, it is really simple. So let’s try a simple example.
The first step is to create a Xaml file with the layout I want. I think the easiest way to do this, is to add a new UserControl in my Silverlight project and then use Blend to design it. But before I can enter Blend, the Xaml file needs to be modified due to the restrictions mentioned before. The UserControl element needs to be changed into something simpler, in my case a Grid. The x:Class attribute must be removed. And in my case, I remove the “LayoutRoot” element as well, leaving me with this
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Grid>
After this, I can enter the realm of Blend. Just remember, no controls and no fancy pre-created stuff.
My loading screen will be a simple little thing. But since I like dark things and want to look different from the standard screen, I have created a black screen with a progress bar and a textblock. The progress bar however, is not the built in type, but one of my own designs. The Xaml looks as this
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Background="Black">
<Grid Height="10" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200">
<Rectangle x:Name="ProgressContainer" Stroke="#FF8E8E8E"/>
<Rectangle x:Name="Progress" HorizontalAlignment="Left" Fill="#FF585858"
StrokeThickness="0" Margin="2"/>
</Grid>
<TextBlock x:Name="ProgressText" VerticalAlignment="Center" Text="0%"
Foreground="#FF828282" HorizontalAlignment="Center" Margin="0,30,0,0"/>
</Grid>
After my layout is done, I move the Xaml file from the Silverlight project into my web project. The loading screen should not be a part of the Silverlight application, it should be loaded separately from the Xap and must therefore be placed in the web project. I would really have liked it if setting the BuildAction to SplashScreen would have copied it for me automatically. Actually, I would have loved a way in general to make this copy possible. That way, the loading screen could have been a part of the Silverlight project and not the web project…but I haven’t found a way to do this nicely. So I do it the hard way.
The next step is to set up the HTML to get the plug-in to use this screen. That part is very simple. Just add 2 parameters to the object tag, the splashscreensource and the onSourceDownloadProgressChanged. The first parameter should point towards the Xaml file, while the other should name a JavaScript function that should handle the event.
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%" id="SilverlightControl">
<param name="splashscreensource" value="ClientBin/LoadingScreen.xaml" />
<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />
<param name="source" value="ClientBin/DownloadScreen.xap" />
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="3.0.40624.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"
style="border-style: none" />
</a>
</object>
The signature for the JavaScript event handler looks like this
function onSourceDownloadProgressChanged(sender, eventArgs) {
}
From the eventargs I can get all the information I need. Or rather the only information I need in this case, the download progress. But first things first, I need to get hold of the elements in my screen. First and foremost the Progress rectangle. This is easy to do. The sender argument will be the root element of the Xaml page, that is in this case the Grid. The grid has a method called findName that will do just that. It will find any child with the specified name. So to get hold of the Progress Rectangle and the ProgressText TextBlock I just have to do this
var progress = sender.findName("Progress");
var progressText = sender.findName("ProgressText");
Next step is of course to have a look at the download progress. This information is available through the eventargs that where passed in. This object will hand us this information through a property called “progress”. The “progress” property will be a double indicating the download progress. So my script will look like this
function onSourceDownloadProgressChanged(sender, eventArgs) {
var progress = sender.findName("Progress");
var progressText = sender.findName("ProgressText");
progress.Width = eventArgs.progress * 196;
progressText.Text = parseInt(eventArgs.progress * 100) + "%";
}
This is something that unfortunately can be a bit hard to test locally. The Xap loading when sitting locally is often so fast that you don’t have time to see the loading screen. This can be fixed in several ways. My personal favorite is to use Fiddler. And how does Fiddler help me to do this? Well, it can simulate slow download speeds. Just fire up Fiddler and go to “Rules” > “Performance” > “Simulate Modem Speed”. However, there are a few problems with doing this.
First of all, even if you use Fiddler to limit the download speed, your Xap might be to small to give you a good look anyway. On the other hand, if you Xap is that little, you might get a way with just a static loading screen since it will only be visible for a very short time. But if you still want to try the JavaScript function out, I suggest adding a “large” file to your Silverlight project. Just remember to set the BuildAction to Content to get it into the Xap.
The second issue is that Fiddler does not interfere with request going to your local machine. This can be solved by first of all moving the application to IIS instead of using the built in web server in VS (Cassini). Although, only doing this will not work. You need get another host name than “localhost”. This is easy. Just open the “host” file in the folder “C:\Windows\System32\drivers\etc\” in Notepad and add a single line saying “127.0.0.1 downloader”. And yeah, remember to set the binding in IIS to use this host header.
After these little tweaks, just open your browser and browse to your test page and have a look at your new loading page.
The project is available for download here: DownloadScreen.zip (57.27 kb). (I haven’t included a “bloat file” so you will have to do that yourself if needed)
I hope you have enjoyed this little piece of information and that you use custom loading screens in future projects. A white standard loading screen just doesn’t look that good if your site has a completely different look and feel when it is done loading.