Radio Button List Box With Seperate Group Name in Silverlight

Multiple radio button list box binding different values of same type.

<Style x:Key="RadioListItem" TargetType="ListBoxItem">
     <Setter Property="Template">
          <Setter.Value>
               <ControlTemplate TargetType="ListBoxItem">
                    <RadioButton x:Name="RadioButtonControl"
                              IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay}"
                              DataContext="{TemplateBinding IsSelected}" Content="{TemplateBinding Content}" />
               </ControlTemplate>
          </Setter.Value>
     </Setter>
&lt/Style>

Implemented the template to the listbox as below.

<ListBox x:Name="SizeFilter" SelectedItem="{Binding Size, Mode=TwoWay}"
          ItemContainerStyle="{StaticResource  RadioListItem}" />

With GroupName:

<Style x:Key="RadioListItem" TargetType="ListBoxItem">
     <Setter Property="Template">
          <Setter.Value>
               <ControlTemplate TargetType="ListBoxItem">
                    <RadioButton x:Name="RadioButtonControl" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay}"
                                     DataContext="{TemplateBinding IsSelected}" Content="{TemplateBinding Content}"
                                     GroupName="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}" />
               </ControlTemplate>
          </Setter.Value>
      </Setter>
</Style>

And here goes my ListBox.

<ListBox x:Name="SizeFilter" SelectedItem="{Binding Size, Mode=TwoWay}" >
     <ListBox.ItemContainerStyle>
          <Style BasedOn="{StaticResource RadioListItem}" TargetType="ListBoxItem" >
               <Setter Property="Tag" Value="SizeFilterGroup" />
          </Style>
      </ListBox.ItemContainerStyle>
</ListBox>

 

Posted in Silverlight | Leave a comment

COM in Silverlight

One of the most surprising features that’s granted to elevated-trust applications is the ability to create COM objects and use them to do pretty much anything. For those who need a history lesson, Component Object Model (COM) is the original standard for component reuse and application integration. It’s the predecessor to .NET, a key part of past and present versions of Windows and still a cornerstone technology for certain tasks (for example, interacting with Office applications such as Word and Excel). Because other applications can provide hooks into their functionality through COM libraries and because these libraries can then be used to
“drive” (or automate) the applications, this feature is sometimes called COM automation. Note COM is an unashamedly Windows-specific technology. Thus, this feature won’t work on non-Windows operating systems, like Mac OS. In the past, before the widespread adoption of .NET, developers often created their own COM components to share and deploy functionality. However, the COM support in Silverlight is not intended for the use of custom COM components. Although this is technically possible, deploying COM components runs into a wide range of configuration and versioning headaches, so it’s not recommended. Instead, the COM support is designed to give your applications a pass into preinstalled libraries, such as those provided by the Windows operating system and other already-installed applications (such as Microsoft Office), and those provided to access the functionality in other components (such as scanners, cameras, and so on). The AutomationFactory class is the entry point to Silverlight’s COM support. It’s found in the System.Runtime.InteropServices.Automation namespace. To use silverlight’s COM support, several details need to be in place. Your application needs to be running out-of-browser, with elevated trust, on a Windows computer. If all these requirements are met and COM support is available, the AutomationFactory.IsAvailable property will return true. Here’s an example method that checks for COM supports and shows an explanatory message if it isn’t available:

private bool TestForComSupport()
{
if (!Application.Current.HasElevatedPermissions)
{
MessageBox.Show("This feature is not available because the application "
"does not have elevated trust.");
}
else if (!AutomationFactory.IsAvailable)
{
MessageBox.Show("This feature is not available because the operating " +
"system does not appear to support COM.");
}
else
{
return true;
}
return false;
}

*******

To create a COM object, you can call the AutomationFactory.CreateObject() method, with the full
COM type name. Here’s an example:

dynamic speech = AutomationFactory.CreateObject("Sapi.SpVoice");

*******

if (TestForComSupport())
{
try
{
using (dynamic speech = AutomationFactory.CreateObject("Sapi.SpVoice"))
{
speech.Volume = 100;
speech.Speak("This is a test");
}
}
catch (Exception err)
{
// An exception occurs if the COM library doesn't exist, or if the
// properties and methods you attempted to use aren't part of it.
}
}

*******

using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))
{
shell.Run("calc.exe");
}

*******

using (dynamic word = AutomationFactory.CreateObject("Word.Application"))
{
dynamic document = word.Documents.Add();
dynamic paragraph = document.Content.Paragraphs.Add;
paragraph.Range.Text = "Heading 1";
paragraph.Range.Font.Bold = true;
paragraph.Format.SpaceAfter = 18;
paragraph.Range.InsertParagraphAfter();
paragraph = document.Content.Paragraphs.Add;
paragraph.Range.Font.Bold = false;
paragraph.Range.Text = "This is some more text";
word.Visible = true;
}

*******
For even more mind-stretching examples, check out Justin Angel’s blog post at
http://justinangel.net/CuttingEdgeSilverlight4ComFeatures

Posted in Silverlight | Leave a comment

Isolated Storage (Silverlight)

Download source code (Visual Web Dev 2010 Express, C#): Solution_IsoStor_08.zip [129 kB].

Download test files (XAP, HTML): Testfiles_IsoStor_08.zip [51 kB].

Environment: Silverlight 4

1.0 – Introduction

Isolated storage for Silverlight provides access to a virtual file system with directories, files and streams and it is used for the same purposes as file I/O for WinForms or WPF, like (temporary) storage of data and application state. The difference is that it does not use the physical file-system and it is independent of the browser cache. It resides on the client.
Data can be shared between Silverlight applications or an application can have it’s own store, isolated from the others.

In this introduction an overview of isolated storage for Silverlight applications, how to manage it and how to save different types of data.

2.0 – Overview

A Silverlight application cannot use the file system of the operating system, all the I/O operations are restricted to isolated storage.
The isolated storage data compartment is an abstraction, not a specific storage location. It consists of one or more isolated storage files, called stores, which contain the actual directory locations where data is stored. All kinds of data can be saved in the store.

Applications for isolated storage are:

  • Temporary storage of data in general.
  • State management.
  • Reducing bandwidth requirements for any given RIA, as data can be cached locally on the client. It reduces network traffic.
  • For improving user experience.
  • Sharing data between Silverlight applications.

Isolated storage has most of the file IO classes from WinForm and WPF applications, with some limitations, they are in the System.IO and System.IO.IsolatedStorage namespaces.
Isolated storage is useful for state management. The System.IO.IsolatedStorage Namespace has a special class IsolatedStorageSettings for storing key-value pairs. This has nothing to do with settings for isolated storage, but rather with application settings (comparable with an ini-file). This subject, however, is too big to be dealt with here, we want to concentrate on file IO with the IsolatedStorageFile and the IsolatedStorageFileStream classes only.
Some of the methods and properties in the IsolatedStorageFile class are for managing isolated storage itself, they are discussed too.

These are the classes and methods to look at:

Table 1 – Isolated storage Classes (System.IO.IsolatedStorage)

Class Description
IsolatedStorageException When an operation in isolated storage fails
IsolatedStorageFile The isolated storage area containing files and directories
IsolatedStorageFileStream Exposes a file within isolated storage
IsolatedStorageSettings Stores key-value pairs in isolated storage

Table 2a – IsolatedStorageFile Class – Quota

Method Description
GetUserStoreForApplication Obtains an isolated storage for the application
GetUserStoreForSite Obtains an isolated storage for applications in a host domain
IncreaseQuotaTo Request a larger quota size
Remove Removes the isolated storage scope and all its contents

Table 2b – IsolatedStorageFile Class – File I/O

Method Description
CreateDirectory Creates a directory in isolated store
CreateFile Creates a file in the isolated store
DeleteDirectory Deletes a directory in the isolated store
DeleteFile Deletes a file in the isolated store
DirectoryExists Indicates whether a directory exists
FileExists Indicates whether a file exists
GetDirectoryNames Get a list with paths of directories
GetFileNames Get a list with filenames from a directory
OpenFile Opens a file using the specified sharing and access options

To make isolated storage easily accessible in code a small class was made with functions implementing the most common methods from the IsolatedStorageFile Class, extended with functions for saving text and byte arrays (Table 3). The class is a simple wrapper without properties.

Table 3 – A utility class for isolated storage (IsoStor_08a)

Method Description
Stor_IsEnabled() Is isolated storage enabled?
Stor_IsAvailable() Is isolated storage available?
Stor_GetInfoQuota() Get available space in isolated storage
Stor_GetQuota() Get quota for the application.
Stor_IncreaseQuota() Increase isolated storage quota
Stor_Remove() Remove the storage for this application
Stor_CreateDirectory() Add a new root directory to isolated storage
Stor_GetDirectoryNames() Get the names of all the root-directories
Stor_DeleteFile() Delete a file in a directory
Stor_DeleteDirectory() Delete a root-directory from isolated storage
Stor_CreateFile() Create a file in a directory
Stor_WriteTextFile() Append text to a textfile
Stor_ReadTextFile() Read all text from a file
Stor_ClearFile() Make the file empty.
Stor_FileExists() Test if a file exists.
Stor_ReadBytes() Get byte array from file
Stor_WriteBytes() Save byte array to file

The solution (see download) has two versions of this class. Class IsoStor_08a obtains user-scoped isolated storage for one application, class IsoStor_08b obtains an isolated store for all applications in a virtual host domain. The latter is used in a test for sharing data between applications. Both classes have the same methods from Table 3.

This is an easy to use set of functions without frizzles. Most of them are discussed below or used indirectly in the tests.

3.0 – The user interface for testing

Most methods from class IsoStor_08a (Table 3) are tested in a Silverlight application with two TextBox controls and buttons for activating the test-functions. The code is in the download.

The intention is to discover how isolated storage works when it is created for an application and removed again and how files can be saved.

Fig. 3.1 – The functions from Table 3 are tested in a Silverlight application, in a web page (screendump). In the left panel 10 random bytes saved to file with ‘Save byte array’, in the right panel the data opened from file again with ‘Open byte array’.
Button Description Function

Save byte array Save data as byte array to a file in IsoStor Stor_WriteBytes
Open byte array Open the file saved with ‘Save byte array’ Stor_ReadBytes
Save text Save data as text to a file in IsoStor Stor_WriteTextFile
Open text Open the file saved with ‘Save text’ Stor_ReadTextFile
Clear test-file Make the test-file empty, without deleting it Stor_ClearFile
Get Directories Get a list with all the directories in the root of IsoStor Stor_GetDirectoryNames
Get Quota Get the size of the quota for this application (MB) Stor_GetQuota
Is IsoStor Enabled Is the storage enabled? (IsolatedStorageFile.IsEnabled) Stor_IsEnabled
App Quota available? Has this application quota in IsoStor? (+ size) Stor_IsAvailable
Remove stor Remove stor for this app (IsolatedStorageFile.Remove) Stor_Remove
Clear (L) Clear the left text panel (shows data to IsoStor) X
Clear (R) Clear the right text panel (shows data from IsoStor) X

The numbers on the buttons correspond with the test-functions in the code (Test_00 .. Test_09).

Saving a file always asks permission from the user to increase the quota from 1 to 5 MB for the first time.
Button ‘Save byte array’ always saves 10 random bytes to a file (0..255). Button ‘Save text’ always saves a string with 100 random characters in the range “abcdefghijklmnopqrstuvwxyz1234567890”.

You can do the tests yourself in a separate page TestPage_User_08.htm with the Silverlight application. It uses the same IsoStor_08.xap as from the solution in the download.
All the details are discussed in the next chapters.

4.0 – Managing isolated storage

Isolated storage is different from standard physical file-access on the client, for a WinForms or WPF application, in that it needs to be configured and managed, it is a virtual file system. The IsolatedStorageFile class has some specific methods and properties for this task.

Isolated storage has three levels of access:

  1. Is isolated storage enabled?
  2. Has the Silverlight application quota in the storage?
  3. Is there enough room in the storage for data?

How much storage applications are using on the client can be found in the Silverlight Configuration dialog. Open this window with Start | Silverlight or with a right click on the Silverlight application in the web page. Each domain (web site) has it’s own quota, the default size is 1 MB but an application can ask to increase this.

Fig. 4.1 – Info about allocated quota on tab ‘Application Storage’ of the Silverlight Configuration dialog.

Another way to get this information is from code. The IsolatedStorageFile Class has the properties AvailableFreeSpace, Quota and UsedSpace for this.


4.1 – Enabling isolated storage

Enable isolated storage in the Silverlight Configuration, tab ‘Application Storage’, check ‘Enable application storage’ (Fig. 3.1) or use the IsolatedStorageFile.IsEnabled property dynamically to see it’s status. It is not possible to enable or disable isolated storage from code.

C# – Is Application Storage enabled? (Stor_IsEnabled)

  using System.IO.IsolatedStorage;
  [...]

  // ---------------------------------------------------------------
  // Date      010111
  // Purpose   Is isolated storage enabled?
  // Entry     None
  // Return    True if enabled.
  // Comments
  // ---------------------------------------------------------------
  public bool Stor_IsEnabled()
  {
      try
      {
          return IsolatedStorageFile.IsEnabled;
      }
      catch (IsolatedStorageException)
      {
          return false;
      }
  }


4.2 – Get the storage as object

The first thing to do when accessing directories and files in isolated storage is to get the storage as object with the GetUserStoreForApplication method. After that you can use it for saving files.

C# – Get the storage as object.

  try
  {
      using (IsolatedStorageFile oStore = IsolatedStorageFile.GetUserStoreForApplication())
      {
          // Get the size of the storage (bytes).
          string sSize = oStore.Quota.ToString();
      }
  }
  catch (IsolatedStorageException)
  {
      // Store could not be accessed.
      // ...
  }

When the application has no quota the GetUserStoreForApplication method creates a store with an initial size of 1 MB.
After that, data can be saved with the IsolatedStorageFile methods and properties (table 2a and 2b). Directory- and filenames are absolute.

In this example the current size of the storage is retrieved with property Quota as a number of bytes. Another useful property is AvailableFreeSpace, for getting the free space (bytes).

IsolatedStorageFile should be declared and instantiated in a using statement. The using statement calls the Dispose method on the object and it also causes the object to go out of scope as soon as Dispose is called.
Always put the code in a try-catch block. You have no guarantee that isolated storage is available and files could be in use by another Silverlight application, a virus scanner or file indexer.


4.3 – Get quota information

IsolatedStorageFile has three useful properties to manage the amount of storage for an application: get the total size of the storage (Quota), the already used size (UsedSize) or the available free space (AvailableFreeSpace). The returned values are in bytes. This info helps to decide if there is enough room in the storage – you can delete redundant files or increase the quota with the IncreaseQuotaTo method.

C# – Get quota information (Stor_GetInfoQuota).

  // Get quota information.
  public string Stor_GetInfoQuota()
  {
      try
      {
          using (IsolatedStorageFile oStore =
                 IsolatedStorageFile.GetUserStoreForApplication())
          {
              string s = "";
              string r = "\r\n";
              s += "Current quota = " + oStore.Quota.ToString() + " byte" + r;
              s += "Space Used = " + oStore.UsedSize.ToString() + " byte" + r;
              s += "Space Available = " +
                           oStore.AvailableFreeSpace.ToString() + " byte" + r;
              return s;
          }
      }
      catch (IsolatedStorageException)
      {
          return "";
      }
  }

C# – Get quota (Stor_GetQuota).

  // Get Quota for the application.
  public long Stor_GetQuota()
  {
      try
      {
          using (IsolatedStorageFile oStore =
                 IsolatedStorageFile.GetUserStoreForApplication())
          {
              return oStore.Quota;
          }
      }
      catch (IsolatedStorageException)
      {
          return 0;
      }
  }


4.4 – Increasing quota

Quota is the size of the total available storage in bytes for an application, or for all the applications in a domain. When a Silverlight application wants to increase quota, with the IsolatedStorageFile.IncreaseQuotaTo method, the user is asked for permission:

Fig. 4.2 – The user is asked for permission if the applications wants for more memory in isolated storage.

Or in code:

C# – Ask the user if increasing quota is allowed.

  // ---------------------------------------------------------------
  // Date      301210
  // Purpose   Increase isolated storage quota.
  // Entry     quota - The new quota in MB.
  // Return    True if quota is increased.
  // Comments  1) The host shows a popup asking the user to approve.
  //           It has buttons Yes (return=true) and No (return=false).
  //           2) Only quota increases are allowed.
  // ---------------------------------------------------------------
  public bool Stor_IncreaseQuota(int quota)
  {
      try
      {
          using (IsolatedStorageFile oStore =
                 IsolatedStorageFile.GetUserStoreForApplication())
          {
              Int64 iQuotaNew = quota * 1024 * 1024;
              Int64 iQuotaCur = oStore.Quota;

              if (iQuotaNew > iQuotaCur)
              {
                  if (oStore.IncreaseQuotaTo(iQuotaNew) == true)
                  {
                      // The user clicked Yes to the
                      // host's prompt to approve the quota increase.
                      return true;
                  }
                  else
                  {
                      // The user clicked No to the
                      // host's prompt to approve the quota increase.
                      return false;
                  }
              }
              else
              {
                  return false;
              }
          }
      }
      catch (IsolatedStorageException)
      {
          return false;
      }
  }

A larger storage is made with the IsolatedStorageFile.IncreaseQuotaTo() method. This method opens a dialog with the question ‘Do you want to increase available storage?‘ (Fig. 4.2), and the user can respond with the buttons ‘Yes’ or ‘No’. The answer is reflected in the return of the IsolatedStorageFile.IncreaseQuotaTo() method with true or false. From the response you can decide what to do next.

This function was tested for an increase to 5MB, 10 MB, 11 MB, 14 MB, 24 MB, 99 MB and 100 MB. So, there seems to be no limit and there are no prescribed discrete values as in previous Silverlight versions. Notice, however that isolated storage is intended for small amounts of data.

It’s only possible to increase the size, decreasing is not possible. However, completely removing the isolated storage for an application is possible with the IsolatedStoreFile.Remove method or via the Silverlight Configuration dialog.


Fig. 4.3 – Each application has it’s own quota.


4.5 – Removing quota

The quota for an application can be removed dynamically with the IsolatedStorageFile.Remove Method. This is the same as when the user removes a storage via the Silverlight Configuration dialog (select the web site + button ‘Delete’). All the directories and files in it are also removed.

C# – Remove quota for this application (Stor_Remove).

  // ---------------------------------------------------------------
  // Date      301210
  // Purpose   Removes the isolated storage scope and all its contents.
  // Entry     None.
  // Return    True if successful.
  // Comments
  //---------------------------------------------------------------
  public bool Stor_Remove()
  {
      try
      {
          using (IsolatedStorageFile oStore =
                 IsolatedStorageFile.GetUserStoreForApplication())
          {
              oStore.Remove();
              return true;
          }
      }
      catch (IsolatedStorageException)
      {
          return false;
      }
  }

Removing quota dynamically seems to work inconsistantly.
After Stor_Remove(), IsolatedStorageFile.Quota often still returns the original size of the store (for an increased size) but the directories and files in it are often deleted. Removing the store via the Silverlight Configuration dialog indeed removes it completely.

Removing isolated storage for an application is only possible when none of the files is in use, and a directory can only be deleted when it is empty. The MSDN library notes that file deletions are subject to intermittent failures because files can be in use simultaneously by operating system features such as virus scanners and file indexers. So, this can be a reason (see the IsolatedStorageFile.DeleteFile Method).

Notice also that method GetUserStoreForApplication or GetUserStoreForSite immediately re-creates a storage (with initial size of 1 MB) when called after a successful Remove. The new storage is empty, of course.


4.6 – Sharing quota between applications

Sharing quota between two or more Silverlight applications from the same user (in the same domain, the same web site) means that both can use the same storage. For example, one application can save data to storage as a result of a user interaction and the other application can open the data to display it. This gives interesting possibilities for combining several Silverlight applications in a web page.
It’s also possible to communicate between Silverlight applications with local messaging. This allows for even more advanced structures. Use the LocalMessageReceiver and LocalMessageSender classes from the System.Windows.Messaging namespace (not implemented).

To obtain the isolated storage for a user for the current application in the domain, use the GetUserStoreForApplication method.

To obtain the isolated storage for a user by all the applications in the domain, use the GetUserStoreForSite method.


Fig. 4.4 – Sharing of data between Silverlight applications combined with local messaging for advanced solutions.

Sharing quota is tested with the code in the download. The solution has two almost identical classes. One class (IsoStor_08a) uses GetUserStoreForApplication to get a storage, the other uses class (IsoStor_08b) GetUserStoreForSite, but both classes have the same methods (Table 3).

This is how sharing is tested:

The solution (download) is build, together with class IsoStor_08b (GetUserStoreForSite) as active class. Two idendical copies (IsoStor_08b_1.xap, IsoStor_08b_2.xap) are then made from the original xap (IsoStor_08.xap) and referenced in two Silverlight applications in a web page. The applications have the same user-interface (Fig. 3.1) with the same functions but they are independent because they are referencing their own xap.
Sharing is tested by saving data to the storage from one application and opening the data from the other.

The test is prepared and carried out as follows:

  1. Change in the code (see download) the class instance for IsoStor_08a to IsoStor_08b in the constructor of MainPage.xaml.cs to get IsolatedStorageFile objects obtained with GetUserStoreForSite.
  2. Build the solution.
  3. Make 2 copies of the \Bin\Debug\IsoStor_08.xap file and name them \Bin\Debug\IsoStor_08b_1.xap and IsoStor_08b_2.xap.
  4. Make an HTML web page TestPage_Share_08.htmwith two Silverlight applications:
    1. Make a new HTML web page (TestPage_Share_08.htm).
    2. Make two copies from the
      id=”_sl_historyFrame_1″
      style=”visibility:hidden;height:0px;width:0px;border:0px”>
      <!– ============= –>
      </td></tr>
      <tr><td>
      <!– ============= –>

      id=”_sl_historyFrame_2″
      style=”visibility:hidden;height:0px;width:0px;border:0px”>
      <!– ============= –>
      </td></tr>
      </table>

      </body>
      </html>

The size of the <object> elements is changed from 100% to width=”630″, height=”330″ to make them fit in the table cells (about the same size as the UserControl) and they link to two different XAP files. The ID’s for the iframe elements are also adjusted to make them unique. When the <object> elements are added to XHTML instead of HTML the & character in the link must be changed to &.

In the web page are two identical copies of the Silverlight application but they use different XAP application packages (IsoStor_08b_1.xap, IsoStor_08b_2.xap). The two applications are looking to the same directory and file and the IsolatedStorageFile objects are obtained with the GetUserStoreForSite; the applications are sharing the same store in the domain. This is proved by copying the file to isolated storage with one application and opening the file with the other application.
Check: when class IsoStor_08a is used instead of IsoStor_08b (which uses method GetUserStoreForApplication for obtaining a store) the test fails.

Note: Mime-type ‘application/x-silverlight-2’ applies to Silverlight 2 and higher.

You can test sharing yourself in a separate page TestPage_Share_08.htm with the two Silverlight applications.


4.7 – Some test results

Isolated storage has it’s own rules for access and creating/removing quota. The user interface has 3 buttons for testing this: ‘Is IsoStor enabled?‘, ‘App quota available?‘ (also returns the size) and ‘Remove Stor‘ (using method Remove). This can be combined with the buttons ‘Save text‘ and ‘Save byte array‘ to see if data is still available in the storage; button ‘Open text‘ and ‘Open byte array‘. Results can also be checked in the Silverlight Configuration dialog, right click on the application.

Some results from this chapter:

  • Enable or disable isolated storage in the Silverlight Configuration dialog. Right click on the Silverlight application or Start | Programs | Silverlight to open it.
  • Before using isolated storage (with GetUserStoreForApplication or GetUserStoreForSite) you can test if the storage is enabled with the IsolatedStorageFile.IsEnabled property.
  • Isolated storage is not accessible when the web page with the Silverlight application is opened in Internet Explorer on a tab secured with ‘InPrivate’. The result is an IsolatedStorageException ‘Operation not permitted‘ thrown by the GetUserStoreForApplication method.
    In Firefox: menu Tools | Stop Private Browsing.
  • The IsolatedStorageFile.IsEnabled method cannot distinguish between a disabled storage in the Silverlight Configuration and a web page running ‘in private’. In both cases the method returns false. So, these two possibilities must be mentioned when communicating with the user.
  • The initial quota is 1 MB to be shared by all of the domain’s applications. When the application has no quota the GetUserStoreForApplication or GetUserStoreForSite method creates a new store with this initial size.
  • Quota group size can be changed.
  • Only quota increases are allowed.
  • A new quota size must be approved by the user. When an application tries to increase quota, a dialog box for the user is shown to approve the request.
  • You can create and delete directories and files in isolated storage.
  • A directory in isolated storage can only be deleted when it is empty. A file can only be deleted when it is not in use.
  • Deleted files or directories cannot be recovered.
  • Quota can be removed entirely.
  • The user can remove the application storage via the Silverlight Configuration dialog (select the web site + button ‘Delete’) even if the application is running.
  • Quota for the application can be also be removed dynamically with the IsolatedStorageFile.Remove Method. The store is removed with all it’s contents.
  • When files are in use, the quota cannot be removed.
  • When quota for the application is removed dynamically, with the IsolatedStorageFile.Remove Method, new quota are created as soon as GetUserStoreForApplication or GetUserStoreForSite is used.
  • Quota can be reserved for only one application in a domain when a store is made with GetUserStoreForApplication.
  • Quota can be shared between Silverlight applications in a domain when a store is made with GetUserStoreForSite.

Fig. 4.6 – How isolated storage is used depends on your creativity (Container house for students [2]).

5.0 – Creating directories and files

The root of the virtual file system is located in an obfuscated folder on the physical file system. Each unique identifier provided by the host maps to a different root, which gives each application its own virtual file system. An application cannot navigate out of its own file system into another.

The IsolatedStorageFile class has methods for creating and removing directories and files in isolated storage (Table 2b). For creating a directory simply use CreateDirectory with the name as parameter (string). The directory is created in the root of the isolated storage.
For creating a file in a directory use CreateFile with the filename (including the directory structure).
The System.IO.Path.Combine method can be use to concatenate directory names and filenames to form a complete path. When a new directory ‘Data‘ is made and a file ‘File_01‘ the result from Combine is ‘Data/File_01‘, which is the correct format for the CreateFile method.

C# – Create a directory in isolated storage (Stor_CreateDirectory).

  using System.IO;
  using System.IO.IsolatedStorage;
  [...]

  string sDirname;       // A directory in the storage root.
  string sFileName;      // A file in the directory.
  [...]

  using (IsolatedStorageFile oStore =
         IsolatedStorageFile.GetUserStoreForSite())
  {
      oStore.CreateDirectory(sDirName);
      return true;
  }

C# – Create a directory in isolated storage (Stor_CreateFile).

  using (IsolatedStorageFile oStore =
         IsolatedStorageFile.GetUserStoreForSite())
  {
      IsolatedStorageFileStream fs =
      oStore.CreateFile(System.IO.Path.Combine(sDirName, sFileName));
      fs.Close();
  }

Use the DeleteDirectory and DeleteFile methods to remove directories and files again (Stor_DeleteFile, Stor_DeleteDirectory).
Use the GetDirectoryNames, GetFileNames, DirectoryExists and FileExists methods to get information about a structure in isolated storage.

6.0 – Saving text

For reading and writing text to a file use the IsolatedStorageFile.FileOpen method which returns an IsolatedStorageFileStream. The stream can be used as parameter for the System.IO.StreamReader or System.IO.StreamWriter. The overloaded FileOpen method has a lot of options for FileMode and FileAccess for all sorts of situations.

C# – Writing data to a text file in isolated storage (Stor_WriteTextFile).

  using System.IO;
  using System.IO.IsolatedStorage;
  [...]

  string sDirname;       // A directory in the storage root.
  string sFileName;      // A file in the directory.
  [...]

  using (IsolatedStorageFile oStore =
         IsolatedStorageFile.GetUserStoreForApplication())
  {
      string sPath = System.IO.Path.Combine(sDirName, sFileName);
      using (System.IO.StreamWriter sw =
             new System.IO.StreamWriter(oStore.OpenFile(sPath,
                 System.IO.FileMode.Create,
                 System.IO.FileAccess.Write)))
      {
          sw.Write(sText);
      }
  }

C# – Reading data from a text file in isolated storage (Stor_ReadTextFile).

  string sText;
  using (IsolatedStorageFile oStore =
         IsolatedStorageFile.GetUserStoreForApplication())
  {
      string sPath = System.IO.Path.Combine(sDirName, sFileName);
      using (System.IO.StreamReader sr =
             new System.IO.StreamReader(oStore.OpenFile(sPath,
                 System.IO.FileMode.Open,
                 System.IO.FileAccess.Read)))
      {
          sText = sr.ReadToEnd();
      }
  }

A file is made empty by opening the file with System.IO.FileMode.Truncate:

C# – Clearing a file (Stor_ClearFile).

  using (IsolatedStorageFile oStore =
         IsolatedStorageFile.GetUserStoreForApplication())
  {
      string sPath = System.IO.Path.Combine(sDirName, sFileName);
      using (System.IO.StreamWriter sw =
             new System.IO.StreamWriter(oStore.OpenFile(sPath,
                 System.IO.FileMode.Truncate,
                 System.IO.FileAccess.Write)))
      {
          sw.Close();
      }
  }

The philosophy for the IsoStor_08 class methods for saving text (and byte arrays) is to make an empty file first (Stor_CreateFile) and then saving data in it (Stor_WriteTextFile, Stor_WriteBytes). A file is made empty again with Stor_ClearFile or deleted with Stor_DeleteFile.
This setup gives more room for experiments – how the IsolatedStorageFile methods react to empty files and it is possible to append data.

7.0 – Saving text as Base64

Base64 code can be saved in the same way as text because it is also text. Data as Base64 is suitable for storing in XML (.resx resourcefiles) but is a universal method for saving all kinds of data. It’s easy to convert a byte array to Base64 and vise versa.

C# – Byte array to Base64.

  using System;
  [...]

  // Convert byte array to Base64 string.
  private string BytesToBase64(byte[] data)
  {
      string sBase64 = "";
      sBase64 = Convert.ToBase64String(data);
      return sBase64;
  }

C# – Base64 to byte array.

  // Convert Base64 to byte array.
  private byte[] Base64ToBytes(string sBase64)
  {
      if (sBase64.Length != 0)
      {
          byte[] byteArray = Convert.FromBase64String(sBase64);
          return byteArray;
      }
      else
      {
          return null;
      }
  }

Fig. 7.1 – After obtaining a storage for an application you can customize it’s contents with a directory structure and files.
(Alligator Self Storage UK: Big or small, we store it all.).

8.0 – Saving data as byte array

A universal way of saving all kinds of data (in isolated storage) is to convert the data to byte array and then streaming the bytes to file. Images can be saved via this route and it is easier to encrypt or compress the data.

The IsolatedStorageFileStream class has a Write and a Read method for saving and retrieving byte arrays to/from file.

C# – Byte array to file.

  // ---------------------------------------------------------------
  // Date      251210
  // Purpose   Save byte array to file.
  // Entry     buffer - The byte array to save.
  //           sDirName - The name for the directory in the root.
  //           sFileName - Name of file in sDirName (no Path).
  // Return    True if successful.
  // Comments  The file must exist. Make a new file with Stor_CreateFile().
  //---------------------------------------------------------------
  public bool Stor_WriteBytes(byte[] buffer, string sDirName, string sFileName)
  {
      bool bRet = false;
      using (IsolatedStorageFile oStore =
             IsolatedStorageFile.GetUserStoreForApplication())
      {
          string sPath = System.IO.Path.Combine(sDirName, sFileName);
          if (oStore.FileExists(sPath))
          {
              using (IsolatedStorageFileStream stream =
                  new IsolatedStorageFileStream(sPath, FileMode.Append, oStore))
                  // new IsolatedStorageFileStream(sPath, FileMode.CreateNew, oStore))
              {
                  try
                  {
                      stream.Write(buffer, 0, buffer.Length);
                      bRet = true;
                  }
                  catch (IsolatedStorageException)
                  {
                      bRet = false;
                  }
              }
          }
      }
      return bRet;
  }

C# – Byte array from file.

  // ---------------------------------------------------------------
  // Date      251210
  // Purpose   Get byte array from file.
  // Entry     sDirName - The name for the directory in the root.
  //           sFileName - Name of file in sDirName (no Path).
  // Return    The byte array from the file.
  // Comments
  //---------------------------------------------------------------
  public byte[] Stor_ReadBytes(string sDirName, string sFileName)
  {
      byte[] buffer = null;

      string sPath = System.IO.Path.Combine(sDirName, sFileName);
      using (IsolatedStorageFile oStore =
             IsolatedStorageFile.GetUserStoreForApplication())
      {
          if (oStore.FileExists(sPath))
          {
              using (IsolatedStorageFileStream stream =
                  oStore.OpenFile(sPath, FileMode.Open))
              {
                  buffer = new byte[stream.Length];
                  stream.Read(buffer, 0, buffer.Length);
              }
          }
          else
          {
              buffer = null;
          }
      }
      return buffer;
  }

9.0 – Security and availability

Isolated storage uses a virtual file system located in an obfuscated folder on the physical file system and it is not meant to be accessed directly, but if someone wants to access it anyhow, it is possible. So, other applications running on the machine may be able to access the data. If you need to store sensitive data in isolated storage, encrypt the data using the classes from the System.Security.Cryptography namespace.

Another practical point is the ease in which quota for an application can be removed, simply with the Silverlight Configuration dialog where you can select the web site and remove the quota with button ‘Delete’ or ‘Delete All’. So, don’t expect that your application settings (and data) are always there. A good solution is to hard-code default application settings in the application itself as a backup.


Fig. 9.1 – Quota are easily removed from isolated storage via the Silverlight Configuration dialog.

10.0 – Summary

Silverlight isolated storage is a safe client-side storage with a virtual file system for saving small amounts of data and application state. All I/O operations are restricted to isolated storage and do not use the file system of the operating system.
A storage can be assigned to one application or to all the applications in a domain, for sharing data.
Implementing Silverlight isolated storage needs little code, it is flexible, and it is easy to use.

11.0 – References

[1] MSDN – System.IO.IsolatedStorage Namespace.
Isolated storage provides safe client-side storage for partial-trust applications.
http://msdn.microsoft.com/en-us/library/system.io.isolatedstorage(v=VS.95).aspx

[2] Prefab Shipping Containers House Students in Architecture Contest.
Student housing complex constructed from 100 repurposed shipping containers.
http://www.truthistreason.net/prefab-shipping-containers-house-students-in-architecture-contest

Thanks to Wim R. Bijlsma (http://wrb.home.xs4all.nl/Main/Index.htm)

Posted in Silverlight | Leave a comment