Isolated Storage aims to enable managed applications to create and maintain local storage. In Windows Phone 7 Silverlight-based applications, all I/O operations are restricted to isolated storage and do not have direct access to the underlying OS file system. Windows Phone application developers owe the ability to store data locally on the phone, leveraging all the benefits of isolated storage, such as providing security and preventing unauthorized access and data corruption from other applications.
As you may image, in Windows Phone 7 programming Isolated Storage manipulation is as important as memory handling in traditional desktop applications. So, in this article we are still going to focus upon the fundamentals associated with Isolated Storage via simple yet typical sample applications.
The sample test environments in this article involve:
1. Windows 7;
2. .NET 4.0;
3. Visual Studio 2010;
4. Windows Phone Developer Tools RTW.
Introducing Isolated Storage
For Silverlight applications in Windows Phone 7, data may exist in several forms. For example, read-only data can be stored in a local file within your application. User-specific data can be stored locally in an area called Isolated Storage. Data can also be stored on the Internet, which can be accessed through Web services.
Figure 1: Data Source in WP7 Silverlight App
In this article, we will only delve into local files manipulation via Isolated Storage. The aim of designing Isolated Storage is to make each Windows Phone applications handle its own independent memory area, not to be affected by other Applications. In this way, applications can only focus upon the development of their own data. Although this in some degree limits the development convenience, it is a good design on the whole. If you need to store and retrieve user-specific information, you might consider using isolated storage.
There are typically two ways to use isolated storage. The first way is to save or retrieve data as key/value pairs by using the IsolatedStorageSettings class. The second way is to save or retrieve files by using the IsolatedStorageFile class.
Figure 2: Two ways to use isolated storage in WP7 Silverlight App
According to MSDN, Windows Phone 7 applications do not have an imposed quota size, considering the case that each application's scenario is different. However, storage resources on a phone are limited, so applications should only store necessary data for subsequent manipulations. In fact, if a Windows Phone has only 10% of storage space remaining, the user will receive a notification of this status. And even worse, the system might exit the application unfriendly.
Next, let's introduce the important classes related to Isolated Storage handling one by one.
The easiest way to put data into Isolated Storage is achieved via the class System.IO.IsolatedStorage.IsolatedStorageSettings. First of all, let's look at the definition of this class.
The class IsolatedStorageSettings implements a dictionary that is designed to store name/value pairs. Obviously, with plentiful support, the IsolateStorageSettings class provides a convenient and easy-to-code alternative for you to have key-value based data to persist in isolated storage.
It is pretty simple to utilize the IsolatedStorageSettings object to store data.
The first thing you'll need is obtain an instance of IsolatedStorageFile. This class represents the file system that you'll be working with on the phone. Besides the simple string data, IsolatedStorageSettings can be used for any key-value storage needs that your application may deal with.
Reading or updating the stored data associated with the special key is also easy.
The following scrap illustrates how to store a Person object and use the
TryGetValue() method to get things back.
Note IsolatedStorageSettings can only support key/value formed data storage. For more complex non-settings data, you may fall back upon the other two classes, IsolatedStorageFile and IsolatedFileStream, and even consider serializing and deserializing operations.
System.IO.IsolatedStorage.IsolatedStorageFile represents an isolated storage area containing files and directories. Since standard Silverlight also provides such support, we only need to care about the changes in Windows Phone Isolated Storage APIs from Silverlight, as follows:
- Remove GetUserStoreForSite
- Quota APIs will reflect that there is no quota.
- Windows Phone applications will not have a limit on the quota for storage on disk.
- Windows Phone applications will only have application storage. Since the application cannot have a site of origin, the site specific storage APIs will not be available to Windows Phone applications.
For more details about IsolatedStorageFile, please refer to the subsequent complete samples.
In Windows desktop-styled applications, System.IO.FileStream plays an important role between the disk file and related memory site. Similarly, in Windows Phone 7 System.IO.IsolatedStorage.IsolatedFileStream can expose a file stream access to a file stored within isolated storage. You can use this class to read, write and create files in isolated storage. Since this class extends FileStream, you can use an instance of IsolatedStorageFileStream in most situations where a FileStream might otherwise be used, such as to construct a StreamReader or StreamWriter. For more details about IsolatedStorageFileStream, please refer to the subsequent complete samples.
The exception is thrown when an operation in isolated storage fails. The most common examples of isolated storage exceptions are as follows:
- Missing evidence. Isolated storage requires evidence (information about the assembly and its origin) in order to determine the identity of the code and connect it to the correct associated file space. Without this information, isolated storage cannot be used.
- Invalid operations. Some FileStream operations are not supported for isolated storage.
Starting from the next section, we'll detail into the concrete usage concerning isolated storage via related examples.
Write and Read Text File via Isolated Storage
To work with Isolated Storage, the first step is to obtain the application related storage area.
Obtain contents in Isolated Storage
Getting the current storage area in the Isolated Storage, we can continue with the subsequent operations - reading and writing them all. Since the Isolated Storage is a virtual file system and the operating system's explorer is unable to check out its internal structure, the preceding demand can only be met by calling the two methods of IsolatedStorageFile. The first is the method
The first line will be used to obtain all the subfolder names under the root folder; the second line is used to return all the subfolders under the specified folder dir1.
The second is the method
The first line is used to obtain all the file names under the root folder; the second line can return all the file names under the specified folder dir1.
Although the above methods is easy to use, they can not be used to display all the contents in the current application specific Isolated Storage. For this, we can extend their functionalities using the two helper methods -
First, let's look at the method
GetAllDirectories. In detail, it first gets specified folder by calling the method
GetDirectoryName. And then, make iteration using the queried result. Finally, returns the whole paths under specified folder in the form of a string array.
The subsequent method
GetAllFiles can retrieve all the files under specified folder. In detail, this method, with the returned value of
GetAllDirectories as parameter, invokes the method
GetFileNames in the system, and then returns a string array composed of the whole paths.
Create folder and file
As soon as getting the isolated storage, we can create folders and files in it. To create a folder, we can directly invoke the method CreateDirectory of the instance of the class IsolatedStorageFile. Note the argument of this method specifies the folder name and the content of the string should be valid; otherwise, an exception IsolatedStorageException will be thrown out.
Also note that only in the case that the target folder does not exist can we create it – if it already exists there is no result to create it again. Moreover, if the argument passed to
CreateDirectory contains two-level directory, both of these directories do not exist, you will create two folders at once in the store. At last, if we add a file to a non-existing folder, and then an exception DirectoryNotFoundException will be thrown out.
Write and read text file
Local file reading and writing is a very useful feature, commonly used in client-side user configuration persistence or temporary store for online document editing tools, and so on. On the basis of the previous example, this section will show you how to add string to a file within isolated storage, as well as how to read characters inside.
In isolated storage, file operations are implemented through the IsolatedStorageFileStream class, so we should first need to obtain an instance of this class. To do this, you can call the constructor of the IsolatedStorageFileStream class or current IsolatedStorageFile object corresponding method
OpenFile to open the destination file to create a file stream. Since IsolatedStorageFileStream derives from Stream, next we can invoke StreamReader and StreamWriter to implement common I/O operations. Here we are going to illustrate this by building a simple text editor.
For brevity, we will omit the XAML code, but focus upon the Behind Code implementation.
After successfully calling the
WriteToFile method, check out the file in the application corresponding isolated store, and you can see the contents of the file has changed. When you click the read button the
ReadFromFile method below will be invoked. The method's task is to read out the content from inside the file TextDocument.txt, so you need to set access to
Next, let's look at the running-time snapshots (the sample page is UseIsolatedStorage.xaml). Figure 3 illustrates the initial snapshot, showing the folders and related files in Isolated Storage.
Figure 3: The initial snapshot – showing the folders and related files in Isolated Storage
Note there is an empty Textbox control in Figure 3. By clicking the control you can populate some text in it via the virtual keyboard. Here, you can click the button "First Write File" to write the screen content into this application related Isolated Storage. After that, clear all the contents in the Textbox control and click the button "Then Read File", and you will see the previously-stored data read back onto the screen.
Starting from next section, we are going to delve into another typical case associated with Isolated Storage manipulation.
Write and Read XML File via Isolated Storage
In my previous article "Windows Phone 7 Silverlight Programming - Handling XML Data" at DotNetSlackers, I introduced how to read and write XML file directly under Windows Phone 7 OS. In this section, however, we can extend this idea to large XML files. In real cases, Isolated Storage plays an important role in a buffering based application.
Now, let's build up a sample page to see how to achieve the above goal.
Create the sample page
Right click the sample project WP7ISO to add a common Windows Phone 7 Portrait styled page named ReadWriteXML.xaml. The XAML markup code is simple, as follows:
Here, we've simple embedded a ListBox control inside the Panel control named ContentPanel. As you've seen, we've utilized the typical data binding methods to render customer data. As for the Code-Behind implementation, it is also simple, as listed below.
Now, let's track to see the model and data access layer related design.
As you may image, since the current Windows Phone 7 OS does not provide direct support for local database operations, the responsibility of storing local data naturally rests upon text, XML, or binary files. In this case, we select to use XML file to store local data. Listing 15 shows parts of the model.
To facilitate the management, we can further encapsulate the above model using OOP techniques, as shown below.
Business Logic Design
First of all, let's look at the whole sketch of business logic layer design in this sample.
Here, we have, via Linq to XML technique, encapsulated the target XML file into an object Student. And further, we encapsulate Student using a List<Student> class. Then, all Isolated Storage related operations are performed inside a series of member methods. Let's next look into some of the important members.
First, look at the helper method
CreateStoreAndDirectory, inside which we aim to obtain this application related isolated store and create the virtual folder "Model".
In this case, we mainly show interest in the
Load method, as follows.
As stressed previously, the main reason to introduce isolated storage is to improve the system efficiency, using Isolated storage as a buffer. In the above code, we use IsolatedStorageFileStream as intermediacy to bind the memory-formed XML file to isolated storage. Then later, when the application comes back to life – revives again from the Tombstoning state (when the if condition is met), we just need to load data from isolate store to memory structure. In such a case, if the XML file is large, the loading speed can be greatly improved. Finally, with simple Linq to XML operation, we assign the data from memory to List<Student> which will be bound to List control in the interface.
Figure 4 illustrates the running time screenshot. In there, the XML data are rendered onto the screen.
Figure 4: XML data rendered onto screen via Isolated storage
At the first when the application gets started, you cannot find anything different. But later, if you click the button Back to navigate away to other applications and back again into the sample page you will find the load speed of the sample application gets increased, which owes to the buffering isolate store mechanism.
The controversy manipulation, storing new data through isolate store to external .xml file, can also be achieved via the following method
Save. But the integrated example should rely on you readers to accomplish.
How about the thing with binary files? There is nearly nothing special. You can refer to the above two sample to accomplish similar targets.
Write and Read Binary File via Isolated Storage
The following demo shows how to copy files from your project to the isolated storage, where the file you want to copy is a binary format, so the code is using BinaryWriter and BinaryReader.
First, the file person.db is a resource file of the project, which means we should set the related
Build Action property to
Resource. Second, the above case indicates a sample to load a binary file from XAP (the first time launching the application) to isolated storage.
On the whole, except for the Isolated Storage related stuff, the main contribution should owe to BinaryWriter and BinaryReader. Besides this, the method Application.GetResourceStream also plays an important role, via which we can succeed in grabbing resource data from the .xap file.
Because the previous sample brings a binary read/write operation, any file that can be manipulated in similar means. For example, you can handle .jpg files through Isolated Storage. And similarly, we are not to give concrete sample any more; readers can look upon it as homework.
Updating and Uninstalling an Application in the Marketplace
As addressed above, in Windows Phone 7 OS, Isolated Storage is equivalent of independent storage in the application, only for use in the program itself and not allowing access by other programs.
In previous Windows Mobile OS, users can see all files through the resources explorer embedded in the phone device, including your own various kinds of resource files, like in PC. But, the case with Windows phone 7 OS is different, no approach helping you see these files, because these files have been packaged into a .XAP file in the form of Content or Resource format when building the project. As you've already known, you can open this .XAP file using some popular compression applications (such as WinZip or WinRar). But, these packaged files in the program during the running time can only be read, not allowing modification. For example, we can use
System.Windows.Application.GetResourceStream() to read such a file to a Stream, but we can't, in turn, change the file.
So if we need to modify a file during the running time of the program, for example to add some text into a text file or to delete some content, how can we achieve this?
The solution is, at the first running time of the application, we need to copy these files into Isolated Storage on the phone. So later our program can read or write from the storage as needed, ignoring the original packaged XAP file.
Actually, using this method also has an extra advantage - when your program has version upgrading need. When the new version download is complete, the user needs first uninstall the old version software. During the period of uninstall all old files in the program will be deleted, but this will have no effect upon the files in Isolated storage. This is because when the new-versioned program gets installed your original files will still remain in Isolated Storage and will not be overwritten.
Memory Consumption on WP7 and Suggested Principles
According to the official file "Windows Phone 7 Application Certification Requirements" on the AppHub (http://create.msdn.com), "An application must not exceed 90 MB of RAM usage, except on devices that have more than 256 MB of memory. You can use the DeviceExtendedProperties class to query the amount of memory that is available on the device and modify the application behavior at runtime to take advantage of additional memory." So, in current situation, we can say: in Windows Phone 7, the memory used by a program tries not to exceed 90M; otherwise, it will probably exit automatically.
Another important fact is if a page has not been released, all of the controls related resources it contains will not be garbage collected.
In Windows Phone 7 operating image resources will consume plenty of memory. So, if all the consumed memory exceeds 90M, your programs maybe hang. The Image controls defined in the XAML files are all static resources, so it is no use to set
image.source=null to try to release the occupied resource through the background C# code. An exception is you can define the Image controls in C# code. In this case, you can succeed in releasing the occupied resources by the Image controls by implementing
image.source=null; or you can, in this case, invoke
LayoutRoot.Children.Remove(Image) to unload them from LayoutRoot.
Therefore, in most situations, for image controls defined in a XAML file, if you want to release memory occupied by these images, the only time may be when you navigate from the Page. So, when developing your factual applications, an important principle is try not to set a page that contains large numbers of image controls as your MainPage, because this MainPage will not be released until the entire program ends.
So, we have enough reasons to propose that:
1. If a program owes a primary interface, then try not to put too many image controls on the main interface or not to set a page with a large image (or many images) as the main page.
2. Try to set a page that wants to play animations and contains a large number of images page as a separate page. As soon as the animations are over or the related images are used leave the page.
3. Facts proves that setting the background of the Panorama control as an image will consume large memory, generally 24M of memory around( and no relevant to the image formats and sizes). Testes say the only solution that can reduce memory consumption is to reduce the height size of the Panorama control. For example, if we reduce the height size of the Panorama control to half, so memory consumption also will decrease half, because it only renders half in the interface.
Another case is you may want to set the background of the Panorama control to gradient. According to my test, this still can consume 17M of memory or so. If set to monochrome (solid color brush), it reduces to around 2-3M. The only thing that does not consume memory is to use no background.
Therefore, before you decide to use Panorama, do check how much memory your program currently has consumed and whether the remained memory is enough for you to load a Panorama.
How about Pivot? It's said that if you add a lot of tabs into a Pivot control as well as put many images inside them, it may hang. To be honest, however, I haven't tried it. You can check this out yourself.
At last, the following scrap of code can help you to make clear when each Page gets released.
With the preceding official limit, your program can be prevented from consuming infinite memory, so that the entire system will not be slowed down. Obviously, Microsoft's first aim of launching Windows phone 7 is to make users experience smoother. Finally, we have enough reason to say with the phone RAM memory getting larger and larger the above memory limit will be cancelled one day.
In this article we've explored the commonly-required Isolated Storage operations in Windows Phone 7 programming. One of the important roles in real cases of Isolated Storage is serving as a buffer. After all, Windows Phone 7 applications generally require high performance, especially as far as large memory-consuming game applications are concerned. When building game applications developers usually have to deal with binary files, such as various kinds of image files, sound or video files, and more, under which cases with the help of Isolated Storage there is also not much difficulty. But, to be honest, we've still scratched the surface associated with Isolated Storage. In later articles, especially in game sample applications, we maybe continue to dig into this topic.
I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...
This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.