Different ways for loading images and files in Silverlight 2 applications

When loading files in Silverlight 2 applications, this can range from images, video, fonts, etc, there are several options available. You might want to call files that reside on another server, files that are embedded into the .xap application or zip files that are downloaded and unpackaged on the client. In this post I’m reviewing the different options available for this, differences between them and how to implement each of the options.

As an example to load the files I’m using a UserControl with an image on it. A very simple example that is clear enough to show the different approaches. All of the examples I'm showing here have a XAML based approach with a code based counterpart, except for the sample for on demand download.

Base UserControl

 <UserControl x:Class="SLLoadResourcesApproaches.Page"
    xmlns="https://schemas.microsoft.com/client/2007" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <Image x:Name="imageElement" Stretch="Uniform" />
    </Grid>
</UserControl>

This just displays the image, nothing more:

image 

Referencing files in the same directory as the Silverlight application (ClientBin directory )

In other words, this is the default location of your .xap file, so files that are located in the same directory as the base application. By default when you create the Silverlight application with a test web site in Visual Studio this is the ClientBin directory. No extra code is needed to load files in this location.

If the file is placed in the ClientBin directory, call the file in XAML:

 <Image x:Name="imageElement" Stretch="Uniform" Source="_DTH8643.jpg" />

Or in code:

 imageElement.Source = new BitmapImage(new Uri("_DTH8643.jpg", UriKind.Relative));

Note: for the above sample you can use a forward-slash preceding the image name to express that it is located relative to the .xap file (same directory in this case). This is important to not as here it is not the root of the domain name (absolute path) that is taken into account. Take this example where I have a sub-directory to ClientBin, I’m referencing the file as /images/imagename.jpg.

image

To reference the file in the images directory in the ClientBin:

 imageElement.Source = new BitmapImage(new 
   Uri("/images/_DTH8643.jpg", UriKind.Relative));

First time I used this it caused some confusion as I'm used to referrring to files in the root of the domain in this way, not in a sub-directory, so it's important to note this difference with Silverlight.

Copying files to ClientBin upon build in Visual Studio

In the case you are using the files directly in your Silverlight application and don't want to copy them manually to the ClientBin directory you can set this in Visual Studio. Note this is a copy to the ClientBin directory of the Silverlight application project, not the test web project you may have created.

Build action: None.

Copy to Output Directory: Copy always.

image

Loading files located outside of ClientBin (.xap location) directory

In the above screenshot I have an image files located in the "images2" directory. To load images from that directory I can enter the full URL of the image:

 <Image x:Name="imageElement" Stretch="Uniform" 
Source="https://localhost:55907/SLLoadResourcesApproaches_Web/
images2/_DTH8643.jpg" />

In C# code:

 imageElement.Source = new BitmapImage(
new Uri("https://localhost:55907/SLLoadResourcesApproaches_Web
/images2/_DTH8643.jpg", UriKind.Absolute));

Referencing files on external web sites

If you want to call images that reside on external sites you can use the standard download method by using WebClient. Remember that cross domain restrictions apply.

Other than that it is just like calling images using the full URL like above.

 imageElement.Source = new BitmapImage(new 
Uri("https://farm3.static.flickr.com/2013/2438725399_4fa3c6eb2f.jpg?v=0", UriKind.Absolute));

There is however maybe a better way to load a file in from an external site where you can better control the loading of your file before showing it in the UI. By using the WebClient class you can download external files on demand, be it from the current origin site or external sites (see below notes on cross domain restrictions). Using the WebClient you can control what to display while the image or file is being downloaded using event handlers. This approach however is not available in XAML but only in code.

1. Create a WebClient object, an OpenReadCompleted event handler and start the download process

 WebClient webClientImgDownloader = new WebClient();
webClientImgDownloader.OpenReadCompleted += new 
  OpenReadCompletedEventHandler(webClientImgDownloader_OpenReadCompleted);
webClientImgDownloader.OpenReadAsync(photo);

2. Set the source to the image in the OpenReadCompleted event handler

  void webClientImgDownloader_OpenReadCompleted(object sender, 
     OpenReadCompletedEventArgs e)
        {
            BitmapImage bitmap = new BitmapImage();
            bitmap.SetSource(e.Result);
            imageElement.Source = bitmap;
        }

Referencing files included in application package (the .xap file, not the assembly)

When you need your Silverlight application to be independent of any files stored on the server separately you can include everything into a single .xap file. The same applies to file that are integral part of the application. If you know a certain file is always used when running the application it makes sense to include it in the .xap file as there is no reason to download it separately. Including files to be part of the package is what we call Content files.

Files that are packaged into the .xap file need to have the Build Action in Visual Studio set to "Content".

image

To call the file from XAML:

 <Image x:Name="imageElement" Stretch="Uniform" Source="/_DTH8643.jpg" />

Calling from code:

 imageElement.Source = new BitmapImage(new Uri("/_DTH8643.jpg", UriKind.Relative));

Because the files is located at the same level in the application package as the assembly in which the code is running, the forward-slash preceding the name is required here as well.

Files can also be located in sub-directories of the application package. You will notice that the directories are also included in the .xap file (as they would in any .zip archive file).

Application resources: calling files embedded in the application assembly (DLL)

As with other .NET assemblies, files can be embedded into the assembly as resources. For Silverlight applications, set the file Build Action to Resource.

image

Referencing resources embedded into the assembly is implemented in the same way as loading files included in the application (.xap). The difference is they are added to the DLL and thus no longer visible in the .xap file if you unzip it. 

In XAML:

 <Image x:Name="imageElement" Stretch="Uniform" 
Source="/_DTH8643.jpg" />

Code call:

 imageElement.Source = new BitmapImage(new 
Uri("/_DTH8643.jpg", UriKind.Relative));

This is working well for the current assembly but if you want to use a file located in a referenced assembly (a Silverlight class library) you will need to add a special reference to indicate the assembly you are calling the file from. This is done by adding the following prefix to calling the file:

/AssemblyName;component/

So, in the example below I'm calling an image from the assembly named ReferencedSlLibrary.

 <Image x:Name="imageElement" Stretch="Uniform" 
Source="/ReferencedSlLibrary;component/_DTH8643.jpg" />

Code call:

 imageElement.Source = new BitmapImage(new 
Uri("/ReferencedSlLibrarys;component/_DTH8643.jpg", UriKind.Relative));

VS 2008 - SL 2 Beta 1 note: you will notice that the image does almost only get displayed in the Visual Studio designer if you set the source in the above manner, even for own assembly files. I'm guessing this is a bug in beta 1.

Embedding fonts

To embed fonts there is actually a specific implementation to call upon font files, see this great post by Tim Heuer on the different ways to do this.