Click here to Skip to main content
Click here to Skip to main content

A Silverlight Introduction for Line-of-Business Applications

By , 30 Aug 2009
Rate this:
Please Sign up or sign in to vote.

Introduction

I believe Silverlight might finally be the solution that binds Windows and Web-apps together, and from that point of view, I'm very interested in it. So, I started following sessions about Silverlight at Microsoft DevDays, reading tutorials, etcetera. I was struck by the amount of tutorials about the animation and graphic possibilities of Silverlight and the small amount of information that can be found about building line-of-business applications. Moreover, the information is much dispersed.

As I'm giving an introduction on Silverlight to a number of developers of a customer of mine, I started to write a small document outlining the basics of Silverlight. This article is based on that document.

I've also included a small sample application demonstrating a number of the topics that are discussed in this article:

Screenshots of the sample application

Note that you shouldn't see this application as a reference application or a 'best practice': it was built with the sole purpose of demonstrating some Silverlight technologies.

To keep the download size low, I didn't include the WMV-movie file or the database records, but I've added a SQL schema file that shall allow you to rebuild the DB schema. You'll have to provide some records yourself though. Note: if you add images to the database, these should be compressed using the DeflateStream class (you'll find an example of this in the Carservice.svc.cs file).

On a side note: this application also uses the following technologies: WCF and LINQ to SQL in a 3-tiered environment.

The application has been built using only controls that come 'out of the box' with Silverlight. If you consider using Silverlight for your projects, you'll definitely want to check out the Silverlight toolkit on CodePlex.

Background

This introduction assumes that the reader doesn't know anything about WPF or Silverlight. Note that this isn't a tutorial: I don't think you'll be able to build a Silverlight application after reading this document. Rather, you should be able to:

  • Find your way in a Silverlight sample application and sample code.
  • Evaluate if Silverlight is a technology you can use in your projects, or not.

This introduction is in no way complete. There are many other features of Silverlight that I haven't highlighted, but I believe most elements you should know about for developing administrative applications with Silverlight are present.

What is Silverlight?

Silverlight is a new framework from Microsoft that is strongly based on WPF (the original name of Silverlight was WPF/E). The principal aim is to build RIAs with it (Rich Internet Applications). This boils down to: browser-based applications that have the look-and-feel, performance, and response of WinForms applications. Since version 2.0, this framework also supports (a subset of) .NET code in the client. This means that .NET code is executed in the browser, allowing much more processing on the client-side without requiring roundtrips to the server (comparable to JavaScript in a webpage).

The code is compiled and placed as a XAP file on the website. The Silverlight application is hosted in an ASP.NET website by using an asp:silverlight-control tag in the page markup.

Browser support of Silverlight

Silverlight is supported in Internet Explorer, Mozilla, and Safari on Windows, Mac, and Linux (although support on Linux is rather limited).

Check this link for a list of supported platforms and system requirements.

WPF

General

WPF is the acronym for Windows Presentation Foundation, and is a totally new way of building UIs. There's no more usage of code (WinForms) or HTML (ASP.NET), but it uses XML: a WPF UI is called a XAML file (pronounced as zamel). Silverlight isn't really the same as WPF in the sense that Silverlight is just a subset of the WPF-possibilities. Nevertheless, you'll find most of the core-technology of WPF in Silverlight, and the differences are getting smaller in each consecutive Silverlight version (the expectation is that given enough time, there won't be any significant difference between Silverlight and WPF).

XAML is just a way of building a user-interface declaratively. Take for example the following piece of C# code:

TextBlock tb = new TextBlock() { Foreground = new SolidColorBrush(Colors.Black),
                   Margin = new Thickness(3), Text = "Name:" };

It is equivalent to the following markup in XAML:

<TextBlock Foreground="Black" Margin="3">Name:</TextBlock>

Note that the element name corresponds to the control name, the attributes correspond to the properties. You can also replace the attributes with child XML-elements. The example below is equivalent to the previous:

<TextBlock Margin="3">
  <TextBlock.Foreground>
    Black
  </TextBlock.Foreground>
  Name:

</TextBlock>

If you want to reference the element in code (for example, to set the Text property of the TextBlock in code), you must add a Name attribute. The value of that attribute will become the name of the variable in code.

Events on controls are declared in the same way as the properties are declared: as attributes. An example of a Button named 'myButton' with a Clicked event:

<Button Name="myButton" Click="Button_Click_3"/>

Finally, some properties of the parent can be (must be) declared on a child control. These properties are called 'Attached properties'.

For example:

<Grid>
  <TextBlock Grid.Row="0" Grid.Column="1" 
           Foreground="Black" Margin="3">Name:</TextBlock>
</Grid>

(Although the Row and Column properties are really properties of the Grid layout-control, they're declared on the child TextBlock control.)

Namespaces

Similar to the using/Imports statements that are used to reference namespaces in libraries in C#/VB.NET, such references must also be declared in XAML.

These namespace references are declared in the root element of the XAML file, and have the following format: xmlns:name_of_the_namespace="reference_to_the_namespace". By default, a Silverlight UserControl has already two namespace references:

<UserControl x:Class="Test.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
...
</UserControl>

Suppose we want to add a namespace 'data' that references the System.Controls.Data assembly, then the declaration would look like this: xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data". Further down in the XAML file, the elements from that namespace will be preceded by 'data':

<data:DataGrid x:Name="datagrid Margin="10">
</data:DataGrid>

Layout controls

To layout different controls in the user-interface, a number of layout controls can be used in Silverlight:

Grid This layout control corresponds to the TableLayoutPanel from WinForms, and allows to layout controls using Column/Row attributes.
StackPanel The controls are placed below (or next to) each other.
DockPanel The controls are docked. The possibilities are: left, right, top, bottom, and fill. This control is available in WPF but not (yet) in Silverlight.
Canvas This layout control allows to position controls using X and Y coordinates.

(Most of the time, you'll use layout controls instead of positioning your controls based on the top and left edges of the form, just to keep the layout dynamic.)

The Grid is without doubt the most powerful layout control when it's about positioning a great amount of controls. The StackPanel is especially handy when positioning a few controls.

Content controls

Some WPF controls have a Content property and can contain other controls as 'content'.

An example of this is the Button. Most of the time, it'll contain just a TextBlock as a content element:

<Button>
  <TextBlock>Click Me</TextBlock>
</Button>

Of course, that one content-element can in turn contain more child elements. For example, a Button that has a StackPanel with multiple controls as content:

<Button>
  <StackPanel Orientation="Horizontal">
    <Image Source="Img/Account16.png"/>
    <TextBlock>Click Me</TextBlock>
  </StackPanel>
</Button>

ItemsControl

Except the content controls that can only contain one element, there are also controls that can contain multiple elements.

Two examples of these are the ComboBox and the ListBox controls:

<ListBox>
  <ListBox.Items>
    <ListBoxItem><TextBlock>Item 1</TextBlock></ListBoxItem>

    <ListBoxItem><TextBlock>Item 2</TextBlock></ListBoxItem>
  </ListBox.Items>
</ListBox>

DataGrid

A (big) difference between Silverlight and WPF where Silverlight is in the advantage, is that Silverlight has a DataGrid out-of-the-box (with WPF, you must use the DataGrid from the WPF Toolkit on Codeplex).

Remark: the DataGrid in Silverlight is located in the assembly System.Windows.Controls in the namespace System.Windows.Controls.Data. It's possible that you'll have to add a reference to this assembly in your project, and you'll also have to add a namespace reference in your XAML file: xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data".

Basically, the DataGrid is quite simple in usage: you let the DataGrid to generate the columns automatically (using the attribute AutoGenerateColumns), or you'll define the columns manually:

<data:DataGrid Name="datagrid" Margin="10" AutoGenerateColumns="False">
  <data:DataGrid.Columns>
    <data:DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" IsReadOnly="True"/>

    <data:DataGridTextColumn Header="Last name" Binding="{Binding Path=Name}"
        IsReadOnly="False"/>
    <data:DataGridTextColumn Header="First name" Binding="{Binding Path=Firstname}"
        IsReadOnly="False"/>
  </data:DataGrid.Columns>
</data:DataGrid>

There are three column types: a DataGridTextColumn, a DataGridCheckBoxColumn, and a DataGridTemplateColumn. The last one is very powerful because it allows to declare any control for the edit- and view-mode of the column. This allows you to define a DataGridTemplateColumn with a ComboBox or a Button (for example).

Resources

WPF and Silverlight allow you to store elements (and variables) in the Resources of the application. This way, you only have to define the elements once and you can reuse them anywhere in your application.

For example: an Ellipse element where the Brush is defined in the Ellipse element itself:

<Ellipse Height="84" Width="92" Stroke="#FF000000">
  <Ellipse.Fill>
    <RadialGradientBrush GradientOrigin="0.75,0.25">

      <GradientStop Color="#FFF0F2F5"/>
      <GradientStop Color="#FF1D6DE2" Offset="1"/>
    </RadialGradientBrush>
  </Ellipse.Fill>
</Ellipse>

There's nothing wrong with this piece of markup, but if you're using the same Brush in other controls, you'll have a maintenance problem if you want to change the colors afterwards. It'll also clutter up your markup unnecessarily.

In that case, it's advised to create Resources and define your Brush in the Resources. Each resource must have a unique identifier, which is the x:Key attribute. Later, you'll be able to reference these resources using this identifier and the StaticResource operator.

<UserControl.Resources>
  <RadialGradientBrush x:Key="mybrush" GradientOrigin="0.75,0.25">
    <GradientStop Color="#FFF0F2F5"/>
    <GradientStop Color="#FF1D6DE2" Offset="1"/>

  </RadialGradientBrush>
</UserControl.Resources>

<Ellipse Height="84" Width="92" 
   Stroke="#FF000000" Fill="{StaticResource mybrush}"/>

Resources can be defined in several places. If the resources are only used in one XAML-file, they'd best be defined at that level.

If the resources are used throughout the application, they can be defined in the App.xaml file (in Application.Resources).

There's also a second XAML Resources file that is used automatically by Silverlight: Themes/generic.xaml. This file can be used for resources of controls that you've created yourself.

Note: in WPF, there's also an element MergedDictionaries that allows to define and use multiple Resource files in your application. This element is only available from Silverlight version 3 on.

Styles

A very powerful aspect of WPF is the possibility to define styles for the controls. A style is comparable to the CSS-technology in ASP.NET, and is a place where a number of properties for a control are defined and then reused in the application.

A very simple example: suppose you want to define a Margin of 3 for your Buttons. Of course, you could do this on a per-button basis:

<Button Name="button1" Margin="3"><TextBlock>Button 1<>TextBlock>

But, you might also define a Style that will be applied to controls of the Button type, and that defines that the Margin is 3:

<Style x:Key="marginButtonStyle" TargetType="Button">
  <Setter Property="Margin" Value="3"/>
</Style>

Hereafter, the Style is applied to the Button(s):

<Button Name="button1" Style="{StaticResource marginButtonStyle}">
    <TextBlock>Button 1</TextBlock></Button>
<Button Name="button2" Style="{StaticResource marginButtonStyle}">
    <TextBlock>Button 2</TextBlock></Button>

(Styles can be defined inline the control, but will mostly be defined in the Resources.)

In WPF, you can also define a Style that must be applied to all controls of a given type. In that case, you'll leave the x:Key attribute out and you won't have to reference the Style in the control:

<Style TargetType="Button">
  <Setter Property="Margin" Value="3"/>
</Style>

(This technique isn't available in Silverlight though, and you always have to reference the Style explicitly.)

Databinding

Databinding is the technique to bind data to properties of controls. In WPF/Silverlight, this is more elaborate than what was possible in WinForms and ASP.NET.

First of all, you must assign a data source to the controls. One way is to use the DataContext property. This can be assigned on the control, but might just as well be done on a parent control, if the data source is the same for all controls of that parent (e.g., a layoutcontainer).

For example, suppose the declaration of a User class:

public class User
{
  public string Name { get; set; }
  public string Firstname { get; set; }
}

In the code-behind of our XAML page, we have a property User wherein we store an initialized User instance. Finally, we assign this User to the DataContext property of the UserControl (that is the root-element, thus the parent of all containing controls):

public partial class Page : UserControl
{
  public User User { get; set; }

  public Page()
  {
    InitializeComponent();

    User = new User() { Name = "Spileers", Firstname = "Xavier" };
    this.DataContext = this.User;
  }
}

In the markup itself, we bind the properties of the controls to the properties of the User object. This happens through the Binding operator:

<TextBlock Margin="3" Text="{Binding Name}"/>
<TextBlock Margin="3" Text="{Binding Firstname}"/>

Note that you can not only bind the Text properties of a control, but almost any property. Moreover, databinding can also be applied to properties of properties (e.g., User.City.Name) which wasn't possible previously in WinForms.

There's also a Mode operator that indicates how the binding reacts. By default, the mode is OneWay which means that modifications to the data object are propagated to the control, but modifications that are applied in the control aren't applied back to the data object.

With the TwoWay mode, the modifications that are applied to the data object will be propagated to the control and vice-versa.

In Silverlight, the binding mode seems to by OneWay by default. In typical input forms, you'll have to change it to TwoWay. An example:

<TextBox Margin="3" Text="{Binding Path=Name, Mode=TwoWay}"/>

In WPF, you can also data bind properties of controls to each other. See the example below where the value of a Slider is used to set the width of an Ellipse element:

<Slider Name="widthSlider" Minimum="50" Maximum="100" Value="75"/>

<Ellipse Width="{Binding ElementName=widthSlider, Path=Value}" Height="50"
    Fill="{StaticResource mybrush}"/>

This isn't possible in Silverlight 2 though, but it is from version 3 on.

Data templates

Using a data template, you can define how objects are displayed in controls.

For example: suppose a listbox that displays a list of User objects (the ItemsSource is assigned in code):

<ListBox Name="usersListBox">
</ListBox>

The disadvantage is that the system uses the ToString() method of the User instance to decide which text will appear in the listbox.

Using the ItemTemplate property, you can define a DataTemplate for the ListItems so that the users in the list are displayed in a more attractive way:

<ListBox Name="usersListBox" Height="50">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">

        <TextBlock Text="{Binding Name}"/>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

Of course, DataTemplates can also be defined in the Resources, so that they can easily be reused in multiple controls.

Animations

WPF and Silverlight allow you to define animations. Basically, an animation is just a transition from one state to another, by modifying one or more properties of controls.

This modification can happen in two ways: gradually in time (fluent), or by changing from one state to another. Although the first way is much subtler than the second, it isn't possible for any type of property. The most important types that are supported are: Double, Color, and Point.

Take for example the following buttons:

<Button Name="button1><TextBlock>Hide button 2</TextBlock></Button>

<Button Name="button2"><TextBlock>Button 2</TextBlock></Button>

Suppose that clicking on the first button must have as result that the second button briefly disappears. This is possible by building an animation that sets the Opacity property of the second button to zero. An animation is based on a Storyboard that can group multiple animations. This Storyboard is named, which can then be used in code to start the animation(s).

This results in the following XAML:

<Button Name="button1" Click="Button_Click">
  <Button.Resources>
    <Storyboard x:Name="buttonanimation">
      <DoubleAnimation Storyboard.TargetName="button2" 
         Storyboard.TargetProperty="Opacity"
         To="0" Duration="0:0:0.25" AutoReverse="True"/>
    </Storyboard>
  </Button.Resources>

  <TextBlock>Hide button 2</TextBlock>
</Button>

(The Storyboard is stored here as a Resource in the Button. Of course, it might just as well be defined on UserControl level.) The animation above will modify a property of type Double (Opacity) and takes a total time of 25/100 second (Duration) to go to a value of 0.0 (To). Finally, the animation resets the property to the initial value before the animation started (AutoReverse=True).

The event-handler in code is:

private void Button_Click(object sender, RoutedEventArgs e)
{
  buttonanimation.Begin();
}

Notice that this animation is very fluent: you can see the button gradually disappear.

You can also accomplish the disappearance by passing from one state to another: these are animations using key frames. Key frames define different states at different points in time:

<Button Name="button1" Click="Button_Click">
  <Button.Resources>
    <Storyboard x:Name="buttonanimation">
      <DoubleAnimationUsingKeyFrames Storyboard.TargetName="button2"
          Storyboard.TargetProperty="Opacity" FillBehavior="Stop">

        <DiscreteDoubleKeyFrame Value="0.5" KeyTime="0:0:0.10"/>
        <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0.25"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
  </Button.Resources>
  <TextBlock>Hide button 2</TextBlock>
</Button>

This animation defines that at 10/100 second, the Opacity property has the value 0.5 and that at 25/100 second, the Opacity has the value 0. FillBehavior=Stop indicates that once the animation is executed, the values should be reset to their initial values.

When executing the animation, you'll notice it's a lot less fluent than the previous one. That is because the transition from one state to another is rather abrupt. That's why animations with key frames will mostly only be used for properties that can't be animated otherwise.

Note: Expression Blend is a must for defining animations.

Control tsemplates

Control templates allow you to define the appearance of controls. This is very complete in the sense that you can design you control from scratch if you want to.

The following piece of XAML represents the control template of a Button:

<ControlTemplate x:Key="mybuttontemplate" TargetType="Button">
  <Grid>
    <Border Name="outerborder" BorderThickness="1" BorderBrush="Blue"
        Background="{StaticResource mybrush}">
      <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>

  </Grid>
</ControlTemplate>

(The ContentPresenter is the placeholder where the content will be placed.)

When creating the control, its control template can be assigned using the Template property:

<Button Margin="3" Template="{StaticResource mybuttontemplate}">

  <TextBlock>Test</TextBlock>
</Button>

Of course, there's also a mechanism to let the control react when the mouse hovers over it or when it's clicked (for example).

All these interactions are managed in Silverlight by the Visual State Manager (shortened to VSM). In WPF, this is governed by triggers, but it's expected that the VSM-concept will also be added to WPF.

The VSM is located in the System.Windows namespace: xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows".

The VSM can describe different states of the control. Animations are used for the transition from one state to another:

<ControlTemplate x:Key="mybuttontemplate" TargetType="Button">
  <Grid>
    <vsm:VisualStateManager.VisualStateGroups>
      <vsm:VisualStateGroup x:Name="CommonStates">
        <vsm:VisualState x:Name="Normal"/>

        <vsm:VisualState x:Name="MouseOver">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="outerborder"
                Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
                To="GoldenRod" Duration="0:0:0.5" />
          </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="Pressed">

          <Storyboard>
             <ColorAnimationUsingKeyFrames Storyboard.TargetName="outerborder"
                  Storyboard.TargetProperty="(Border.Background).(
                  GradientBrush.GradientStops)[0].(GradientStop.Color)">
               <DiscreteColorKeyFrame Value="Yellow" KeyTime="0:0:0"/>
             </ColorAnimationUsingKeyFrames>
             <ColorAnimationUsingKeyFrames Storyboard.TargetName="outerborder"
                 Storyboard.TargetProperty="(Border.Background).(
                 GradientBrush.GradientStops)[1].(GradientStop.Color)">
               <DiscreteColorKeyFrame Value="GoldenRod" KeyTime="0:0:0"/>

             </ColorAnimationUsingKeyFrames>
           </Storyboard>
         </vsm:VisualState>
       </vsm:VisualStateGroup>
     </vsm:VisualStateManager.VisualStateGroups>

   <Border Name="outerborder" BorderThickness="1" BorderBrush="Blue"
        Background="{StaticResource mybrush}">

     <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
   </Border>
 </Grid>
</ControlTemplate>

There are two states defined in this example: MouseOver and Pressed. In the first state, the button will change color; in the second state, the backcolor of the button is modified.

Navigation between pages

Navigation between pages isn't that easy in Silverlight 2. A Silverlight application has a root-visual element, and all other elements are children of this root element. By default, the page that the solution starts with is the root-visual element (see the App.xaml.cs file).

private void Application_Startup(object sender, StartupEventArgs e)
{
  this.RootVisual = new Page();
}

The root-visual can't be replaced by another User Control once the application is started. But you can simulate navigation by providing a custom root-visual element and setting the content of that custom element on the fly. For example, start by building an inherited UserControl where a UIElement can be passed through and be set as Content:

public partial class NavFrame : UserControl
{
  public NavFrame()
  {
    InitializeComponent();
  }

  public void Navigate(UserControl content)
  {
    this.Content = content;
  }
}

Set this User Control as root-visual element of your application (in App.xaml.cs) and provide methods to navigate to other User Controls:

private Page _page1;
private NavFrame _frame;

private void Application_Startup(object sender, StartupEventArgs e)
{
  _frame = new NavFrame();
  this.RootVisual = _frame;
  NavigatePage1();
}

public void NavigatePage1()
{
  if (_page1 == null) _page1 = new Page();
  _frame.Navigate(_page1);
}

In code, you can call these methods to navigate to other pages.

private void Button_Click(object sender, RoutedEventArgs e)
{
  (Application.Current as App).NavigatePage1();
}

Note: Silverlight 3 has a navigation-framework that simplifies all this and also provides support for the Back and Forward buttons in the browser.

Integrating media

Silverlight provides a MediaElement control for playing media.

<MediaElement Name="mediaPlayer" />

Silverlight 2 supports the following formats: WMV, WMA, MP3, WMVA,WMVC1, and ASX. Of course, it's not interesting to package the media files in the Silverlight project itself (or they'll be downloaded integrally before starting the application); they should be streamed from the website when needed. It's interesting to note that the Silverlight application only knows the path to the location of the XAP-file (default: Clientbin): all paths are relative to this location. A good practice is to make subfolders in this directory and place the media in there:

Silverlight folder structure

This file can be reached by the following code:

Uri uri = new Uri(Application.Current.Host.Source, "Media/Fiesta_car.wmv");
mediaPlayer.Source = uri;

(The code above is in the event handler of a Play-button that will start the playback of the media)

You can place the media anywhere else in the website, but the path should then be relative to the ClientBin folder. If the media file is placed in the root of the website, the code would be:

Uri uri = new Uri(Application.Current.Host.Source, "../Fiesta_car.wmv");
mediaPlayer.Source = uri;

Communication between client and server

There are only limited technologies that are supported by Silverlight for the communication between client and server: SOAP 1.1 Web Services and REST services are about the only mainstream possibilities (there are a couple of others, but they're not that easy to implement).

The easiest way to provide services for your Silverlight application is to build them using WCF. Taking into account the restriction in the previous paragraph; this means we must define a service with a bindingtype of basicHttpBinding (SOAP 1.1) or webHttpBinding (REST).

In code, the service can be referenced just as you would in a 'regular' WinForms or ASP.NET application: Visual Studio will generate a proxy for you. You'll notice that all methods can only be invoked asynchronously: this means events will have to be used to receive the return state of the call to the server.

By default, Silverlight can only invoke services that are placed in the same domain and have the same port number (e.g., www.tri-s.be:80) as the website the application originated from. To consume a service that is placed in another domain (or has a different port number), a policy file must be provided and placed in the root of the web application on the server.

The policy file must be called clientaccesspolicy.xml and has a similar content:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>

      <allow-from>      
        <domain uri="*"/>
      </allow-from>      
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>      
    </policy>

  </cross-domain-access>
</access-policy>

The sample policy file content above allows all traffic to any domain and to any port.

Note: Silverlight has no support for DataSet/DataTable/DataRow objects! Thus it makes no sense to build services that return any of those objects.

[Update: there are alternatives available that emulate the DataSet/DataTable/DataRow functionality (Silverlight Dataset, for example). Thanks to Dewey for pointing this out.]

Storing data locally

Silverlight allows an application to store data locally on the PC of the user. This data can only be placed in IsolatedStorage, which is a location where the user isn't able to retrieve it. You can compare storing data in IsolatedStorage with cookies from a website.

An example of code that stores data in IsolatedStorage:

using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
  using (IsolatedStorageFileStream stream = file.OpenFile("app.data",
      System.IO.FileMode.Create))
  {
    using (StreamWriter writer = new StreamWriter(stream))
    {
      // write data with writer.Write
    }
  }
}

To retrieve the data from IsolatedStorage, the following code can be used:

using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
  if (file.FileExists("app.data"))
  {
    using (IsolatedStorageFileStream stream = file.OpenFile("app.data",
        System.IO.FileMode.Open))
    {
      using (StreamReader reader = new StreamReader(stream))
      {
        // read data with reader.Read
      }
    }
  }
}

If you want to read files from the client machine where the application is executed, there's an OpenFileDialog you can use (the file can be read, but with approval of the user). There isn't an equivalent SaveFileDialog, though.

[Update: from Silverlight 3 on, you can use the SaveFileDialog in Silverlight applications to store files locally. Thanks to Jemery Likness and Dewey for pointing this out.]

Printing in Silverlight

Sending output to a printer on the client isn't supported in Silverlight. Your only alternative is to navigate to an ASP.NET page that contains the data to be printed. Bummer!

[Update: you can export the data in a file (a spreadsheet, for example) and let the user save this to the client PC using a SaveFileDialog. You can also export the complete visual element to a graphical file if you wish (see the comments section below).]

History

  • 2009-08-15: Submitted to CodeProject.
  • 2009-08-31: Added a few updates.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Xavier Spileers
CEO TRI-S bvba, Cogenius bvba
Belgium Belgium
I'm working since 1999 in an IT environment: started developing in PROGRESS 4GL, then VB6 and am working since 2003 with C#. I'm currently transitioning to HTML5, CSS3 and JavaScript for the front-end development.
I started my own company (TRI-S) in 2007 and co-founded another one (Cogenius) in 2012.
Besides being a Microsoft Certified Professional Developer (MCPD) I'm also a Microsoft Certified Trainer (MCT) and am teaching .NET and JavaScript courses.
Follow on   Google+

Comments and Discussions

 
GeneralGood work, needed to be written PinmemberEnda Mannion30-Aug-09 23:23 
GeneralGreat Intro PinmemberRory van der Berg30-Aug-09 20:07 
GeneralThanks PinmemberMycroft Holmes28-Aug-09 14:20 
GeneralGreat Article, but... PinmemberDewey21-Aug-09 11:52 
GeneralRe: Great Article, but... PinmemberXavier Spileers21-Aug-09 20:57 
Generalmy 5 PinmemberBinoy Patel21-Aug-09 10:44 
GeneralThere are workarounds for printing ... PinmemberJeremy Likness21-Aug-09 9:38 
GeneralRe: There are workarounds for printing ... PinmemberDewey21-Aug-09 11:59 
GeneralRe: There are workarounds for printing ... PinmemberXavier Spileers21-Aug-09 20:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 30 Aug 2009
Article Copyright 2009 by Xavier Spileers
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid