Author: Mike

WP7: Images in Secondary Tiles do not appear

Problem: Background Images in secondary tiles do not appear if using remote images.


<wp:BackgroundImage> and <wp:BackBackgroundImage> can use remote URLs, however, the domains need to be included in the Approved URLS list. For example:

// Lists domains that can send tile updates and so forth as push notifications.
// Only these authorized domains will be allowed by the shell to push new tiles to the phone

var ListOfAllowedDomains = new Collection<Uri> {
new Uri(@"http://i."), new Uri(@"") // e.g. if you published a webservice at — put "" here.

By including the domains in the ‘allowed list’ your background images will show up.



Windows Phone Push Notifications: Frequently Asked Questions

Updated March 3, 2013 – added clarifications around the use of certificates.
The following is a collection of FAQs regarding Windows Phone Push Notifications.

Q: How can I get started with Push Notifications?
A: A good way to approach Push Notifications is using a known working sample. Entire sample including client and server code here. Once you get the sample working, you can transfer that to an actual application. This way you can be sure you are composing the push notifications correctly. I would they suggest they get the sample working and then compare that to how they are doing the same notification type.

Q: Do we have to get a new URI if the original URI was received more than 30 days ago?
A: No. As long as the URI has not changed, you can continue to use the URI.

Q: How do we know if the URI has changed?
A: When the app starts, do an HttpNotificationChannel.Find and compare to the previously received channelURI stored in isolated storage. If different, update the web service registration with the new channelUri. If empty, recreate the Channel. See the file MainPage.xaml.cs in the sample here where this logic has been implemented. Note that it is a best practice to send along with the URI information that uniquely identifies the device (DeviceExtendedProperties.GetValue("DeviceUniqueId"). You can use this information when re-registering channel URIs with your web service to replace the existing (invalid) URI with the new one.

Q: How can we tell at the web service if the URI we are sending to the MPNS is still valid?

A: The MPNS will return a 404 response code with one the following notification statuses if the URI is not valid:

Response Code NotificationStatus DeviceConnectionStatus SubscriptionStatus
404 Not Found Dropped Connected Expired
404 Not Found Dropped Temporarily Disconnected Expired
404 Not Found Dropped Disconnected Expired

Note that your web service should stop sending notifications to this URI and un-register it, if the MPNS returns 404 (Dropped).

Q: What causes the MPNS to return the 404 (expired) response code?
A: The following conditions will cause a channel URI to become expired:
1) No activity for 30 days (the channel uri is not used).
2) The device is unable to connect with the MPN server for 30 days. In this case, MPN will return the 412 (inactive) response code, if it cannot connect within 30 days, it will return 404 (dropped).
3) If the xml payload of the notification request is not valid, MPNS will invalidate the channel uri and return 404.

When the application restarts it will receive a new channel URI, which should replace the current (expired) channel URI registered with the web service.

Q: What causes the MPNS to return the 412 (inactive) response code?
A: If the device has been off or otherwise cannot connect with the MPNS it is considered ‘temporarily disconnected’. When the device is in this state, the MPNS will return:

Response Code NotificationStatus DeviceConnectionStatus SubscriptionStatus
200 OK Received Temporarily Disconnected Active

If the web service sends another notification to this URI and at least 90 minutes have passed since the last ‘temporarily disconnected’ notification, MPNS flags the URI ‘inactive’ and will return the 412 response code. In this state, MPNS stops attempting to connect to the device. Note that temp disconnected and inactive are both natural states for a mobile device and shouldn’t be viewed negatively. Commonly 30-40% of devices show temp disconnected at any one time and 10-20% show inactive because mobile devices transition between network conditions and situations frequently.

Q: Besides sending a notification request to MPNS, is there any other way to know if a channel uri (device) has transitioned to the ‘inactive’ state?
A: No. Previous documented was a callback mechanism where authentication notifications could receive a callback if the device transitioned from active to inactive. This has been deprecated and removed from the documentation.

Q: If the PNS is no longer attempting to connect to the device, when does it start communicating again?
A: The PNS will attempt to connect to the device when the Web Service sends the next notification request. The response code returned reflects the devices state (200 – URI OK, 404, URI invalid, 412, URI OK, Device out of communication)

Q: What does the PNS response code 200 suppressed mean?
A: You can receive the suppressed status when for a:

  • Tile notification if the user hasn’t pinned the tile
  • Raw when the app is not in the foreground
  • Toast and Tile when the device is in low battery state

Q) What is the limit of notifications I can send to the users of my app?
A) By default, the limit is 500 notifications per channel URI per day. So if you have multiple notifications (say Toast and Tile) in your application, you can send 500 of each type. That is 500 of each type of notification per device / user. For example, if you have 100 users of your application and 1 type of notification, you can send up to 50,000 (1 * 500 * 100) notifications per day. Authenticated notifications are unlimited.

Q) How do I setup authenticated notifications?
A) Follow the guidance here: Setting Up an Authenticated Web Service to Send Push Notifications. Pay particular attention to the set up of the certificate. For more information on setting up the certificate, see here: No-quota push notifications using a root Certificate Authority.

Q) What can cause a 401 (Unauthorized) status returned when attempting to send an authenticated notification?
A) Can can get a 401 if the Service Name in the certificate does not match the service name parameter in the HttpNotificationChannel constructor. Also, the client will receive a URI with an ‘http’ prefix. If functioning properly HttpNotificationChannel  will return a Uri with an ‘https’ prefix.

Q) I am setting up authenticated notifications and am getting back a 403 status code in my web service code. What is going wrong?
A) Generally, a 403 (forbidden) status is what you would get if either you are not including a certificate in the POST request or it is not a valid/trusted cert. Note that the certificates need to be deployed onto the web servers sending the requests. These certificates should include the private key. (The certificate uploaded to Microsoft should NOT include the private key.) If using an intermediate certificate, ALL of the certificates in the chain should be added prior to the POST request (see below).  When submitting your application to Marketplace, you will also need to associate your application with the appropriate certificate. This is done in the ‘describe’ step.

Q) How do I include a certificate(s) in the POST request?
A) If you are using .NET in your server code, you can add the certificate to the HttpWebRequest as follows:

Request.ClientCertificates.Add(new X509Certificate2("[PathToCertificate]", "[Password]"));

If you are using Ruby, you can add the certificate as follows:



SERVER_CERT_FILE = "certs/freshCA.crt"

CERT_FILE = "certs/s2 at magnesium.crt"

CERT_FILE_KEY = "certs/s2 at magnesium.key"

require ‘net/https’

https =‘fresh’, 443)

https.use_ssl = true

#client certificates

https.cert = )

https.key =, ‘panza’)

#server certificate

https.ca_file = SERVER_CERT_FILE

https.verify_mode = OpenSSL::SSL::VERIFY_PEER     #VERIFY_NONE

https.read_timeout = 120

https.start do |https|

  request =‘/notes/test_auth’)

#  request.basic_auth ‘s’, ‘x’

  response = https.request(request)


  puts response.body



Q) In the code above, does this mean the private certificate (definition below) is sent as part of the request?
A) No. The private certificate is used to sign the request. The server then uses the included public cert to decrypt the request.

Q) When do I use a private certificate and when do I a public certificate?
A) First some definitions: a private certificate is one that includes the private key or is used along with a separate key (.key) file. A public certificate is one that does not include the private key. Note that with push notifications, you will use both private and public versions of your certificate.

Q) When do I use the public certificate? When do I use the private?
A) Upload certificate to Dev Center: Public
Install certificate on my web server certificate store: Private
Certificate included with POST request to MPNS: Private

Q) What can cause a 409 to be returned from the MPNS?
A) A 409 is returned when using authenticated notifications and the certificate has expired. You will need to submit a new certificate.



More Application Optimizing for 256 MB Devices

Background Tasks

Make sure you have exception handling in your Background Task scheduling code. This prevent your app from crashing when run on 256MB devices, if the maximum number of tasks have been scheduled and allowed and if Background Tasks have been disabled by the user. For example:

catch (InvalidOperationException exception)
    if (exception.Message.Contains("BNS Error: The action is disabled"))
        MessageBox.Show("Background agents for this application have been disabled by the user.");
    if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
        // No user action required. The system prompts the user when the hard limit of periodic tasks has been reached.
catch (SchedulerServiceException)
    // No user action required.
    PeriodicCheckBox.IsChecked = false;

The ability to run code truly in the background is a great feature of Windows Phone 7.1. However, your apps should not be dependent on background tasks. Why? For three reasons:

  • PeriodicTasks can be disabled on an app by app basis. Check out Settings | applications | background tasks on your phone. You will see the list of applications that are using background tasks. Here the user can disable your applications use of background tasks.
  • There is a maximum number of PeriodicTask tasks that can be run. Once this limit is hit, no further tasks can be scheduled.
  • PeriodicTask and ResourceIntensiveTask are not supported on 256MB devices. However, you can include code for these in your application – just understand that these tasks will not run on this class of device. This makes it easy to write a single application that will run on all devices types. In fact on these devices, you will see the ‘background tasks’ is still part of the Settings menu (Settings | applications | background tasks).

If your app is running on a 256 device and includes background tasks, you will see that they are disabled in the applications settings (Settings | applications | background tasks | advanced). See in the screen shot (running the 256MB emulator) below, the background tasks included in the application ‘BackgroundAgentSample’ are disabled.


When the maximum number of PeriodicTasks have been scheduled, and you attempt to add another, a InvalidOperationException exception is thrown. The exception message is ‘BNS Error: The maximum number of ScheduledActions of this type have already been added.’ On 256MB devices, this is called anytime you attend to add a scheduled task since the maximum number of PeriodicTasks allowed on these devices is zero.

Note: On premium devices, if you attempt to call ‘Add’ and background agents have been disabled, the exception InvalidOperationException is thrown.

Full SDK sample here.





Additional Best Practices

Optimizing Apps for Lower Cost Devices
Developing for 256-MB Devices
Best practice tips for delivering apps to Windows Phone with 256 MB – Nokia Developer Wiki

Performance Measurement Tools in Windows Phone SDK 7.1

The following is a summary of some of the performance measurement tools available from Microsoft for Windows Phone applications.

Marketplace Test Kit – Automated tests for peak memory usage, launch time, app closure, and back button.

These tests are part of the Windows Phone 7.1 SDK. To launch the tools, right click on your project in Visual Studio and select ‘Open Marketplace Test Kit’.

Test Name

Test Description

Launch time

Validation of application launch time.

Peak memory consumption

Validation of application peak memory consumption

Application closure

Validation of all exceptions being handled and application not closing unexpectedly.

Use of Back Button

Validation of proper behavior when pressing the Back button.

Frame Rate Counters for Drawing Performance

To enable:

Application.Current.Host.Settings.EnableFrameRateCounter = true;
Microsoft.Phone.Shell.SystemTray.IsVisible = false; // System Tray not visible 


Render Thread FPS: The number of frames per second that the independent simple animations and rendering thread is using. Keeping around 60 will provide a great experience, while a number of 30 fps will begin to show a poor experience to the end user.

Under 30 fps this counter will turn red in post-beta builds.

User Interface Thread FPS: The number of fps that the primary user interface thread is experiencing. Property change notifications, data binding, primary managed code execution, and animations not handled on the render thread use this threads’ resources.

Turns red when the count is at or below 15 fps.

Texture Memory Usage: A specialized memory counter indicating the video memory used for storing application textures.

Surface Counter: A count of the number of surfaces that are passed to the graphics chip.

Intermediate Texture Count: The number of intermediate textures created for compositing.

Screen Fill Rate: A metric representing the number of complete phone screens being painted each and every frame.

Memory APIs for measuring / logging memory usage

long applicationCurrentMemoryUsage = 
long applicationPeakMemoryUsage = 



Windows Phone 7: New App Hub Tips



Todd Brix gives a summary here of the new features included in the App Hub Update that went live on July 18th. In this post I’ll review a couple of the new features and tips for using them.

App Name now determined by XAP, not entry in App Hub.

Previously you provided the application name in the description step (step 2) See screenshot below. You needed to specify this for each language your application supported. (See below.)

Pre-July 2011 App Hub Update - app name provided by developer for each language app supported.

Now with the App Hub update, the application name is derived from the Title attribute of the App element in WMAppManifest.xml:

<App xmlns="" ProductID="{xxx5d2d6-ebb1-4e5b-bd12-7e1371696e80}" Title="People and Places" 
       RuntimeType="Silverlight" Version="" Genre="apps.normal" 
       Author="Mike Francis" Description="" Publisher="Mike Francis">

This is great improvement since now the application title is maintained in one place: your application. See this blog post for information on localizing the application title.  App Hub will automatically retrieve the appropriate localized application title for each supported language. See here for a sample project with this implemented. Try creating a test submission (you can delete it later) and upload the resulting XAP file from the sample. Note how App Hub is creating a language version for each language supported. Also note how the localized application name is automatically populated.


Default Language now must be specified in Project Settings

As stated in this forum post, the App Hub now requires a default language specified in your application. This is the ‘Neutral Language’ assembly setting in Project settings.

  1. Right Click on your project in Solution Explorer
  2. Application | Assembly Information. . .
  3. Neutral Language
  4. Pick a specific default language. For example for English:


App artwork can now be specified in one click!

In the ‘Describe’ section (step 2) of your application submission, you provide the screenshots and icons that are used by the PC and Phone versions of Marketplace. Another nice AppHub feature is the ability to upload all of the artwork at once. You can do this as long as you have the art work in the same directory. For my application, I have created a directory <Project Name>\Images\Marketplace and placed my icons and screenshots there. Then when submitting my app, in the ‘Artwork’ section of step 2, I click ‘Browse”, and multi-select all of the artwork in this folder. App Hub intelligently associates the correct size icon with the corresponding App Hub icon slot. See video below.

App Hub: One click application art upload

Tip: This feature reads the screenshot images in alphabetical order, so if you care about the order of your screenshots, rename them so that the filenames are in alpha-order. This way when the tool reads in your screenshots, they will be in the order you expect. For example, (1ScreenShot.png, 1ScreenShot.png, etc.)

screenshots in alpha order



Windows Phone 7: Login UI Sample Code and Coding4Fun


The Coding4Fun library ( for Windows Phone 7 includes many super useful classes that will save you time when writing Windows Phone 7 applications. My favorite is their implementation of very the professional looking and easily extensible user prompts.

While a good assortment of prompts, utilities and other controls have been implemented in coding4fun, what is missing is a login prompt. In this post I’ll review how I’ve used Coding4Fun to create a login prompt.

Can’t I just use a login page?

Many developers have struggled with the Microsoft enforced application navigation flow that mandates:
1) Pressing the Back button must return the application to the previous page or return to any previous page within the back stack.
2) Pressing the Back button from the first screen of an application must close the application.

These rules are difficult to reconcile with an application that has a login prompt on the first page. A couple of problems with this:
1) After the user has successfully logged in, and they have navigated away from the login page, it is confusing if pressing BACK returns them to the Login screen. The expectation is that once they have logged in they should not see the login screen again.
2) Even if you structure the program to navigate to the Login page automatically from the main page if the user has not yet logged in, this gets rid of the ‘BACK navigates to the Login screen’ problem, but it violates the first rule above where BACK on the first screen should exit the app.

See Peter Torr’s article, Introducing the concept of “Places”, for a way to think of ‘places’ and ‘transient UI’. In Peter’s article, he recommends one way to handle the login scenario is with the use of a popup. Enter Coding4Fun.

How It Works

The Coding4Fun’s MessagePrompt class, includes a Body property that you can use to add code on the fly. For example:

messagePrompt.Body = new TextBlock { Text = "Hello World!", Foreground = new SolidColorBrush(Colors.Green),

FontSize = 30.0}

I extended this idea to include, a user control ‘LoginUserControl’ which contains the XAML layout and Username and Password members which are databound to the user control.

In the code below I instantiate the LoginUserControl control, add it to the Body member of an instance of MessagePrompt, display the prompt, and process the user results.

private void Button_Click(object sender, RoutedEventArgs e)
    var luc = new LoginUserControl(); // Customer user control with Login UI

    MessagePrompt messagePrompt = new MessagePrompt(); // Coding4Fun extensible MessagePrompt
    messagePrompt.IsCancelVisible = true; // Show cancel button
    messagePrompt.Body = luc; // Add user control as body of MessagePrompt
    messagePrompt.Completed += (str, res)=> // Handler for MessagePrompt user action
       if (res.PopUpResult == PopUpResult.Cancelled)
            luc.Username = luc.Password = "";
            MessageBox.Show("Login Cancelled");
            MessageBox.Show(string.Format("Username: {0}, Password: {1}", luc.Username, luc.Password));

You can download the sample code here.


Windows Phone 7: Be Careful with that Product ID!

A couple developers I have been working with have had a problem with their application crashing during certification testing, or their app not working as expected after being published. This problem was difficult to debug since the app worked fine for the developer, but would crash out of the gate during testing. After some investigation, we found that the developer was relying on the Product ID to be a known value.

The Product ID is a GUID used to identify your application in the Windows Phone installed application list. This value stays the same across application updates. The Product ID is not controlled by the developer, but is assigned during the ingestion process. That is, the value created by Visual Studio and stored in WMAppManifest.xml, is not the value that will be used when the application is published.

If you are relying on the Product ID to be a certain value – it won’t be what you expect, when your application is published.

<App xmlns="" 
      Title="BestAppEver" RuntimeType="Silverlight" Version="" Genre="apps.normal"
      Author="BestAppEver author" Description="Sample description" Publisher="Cookie1">

Here are a couple of workarounds to consider:

  1. Instead of using the Product ID, use a private scheme to store the unique value your app needs.
  2. If your really need to use the Product ID, you can leverage the way App Hub works. That is, the Product ID is assigned early on in the submission process. Specifically, in Step 1 when you upload your app. You can upload a preliminary version of your app and not submit it for testing. You can then use this Product ID in your code. When your application is ready for submission, you can re-upload your app, overwriting the preliminary version with the final version. The Product ID will not change. See below for sample code on how to read the Product ID at run-time.

To see the Product ID as assigned by Product ID, in your “my apps” list on the dashboard, click on the name of your submission.


Here, you can see the Product ID and the Deep Link. This will not change for this submission.


Code to read the Product ID at run time:

public static string GetProductId() 
    System.Xml.Linq.XElement xml = System.Xml.Linq.XElement.Load("WMAppManifest.xml");
    var appElement = (from manifest in xml.Descendants("App") select manifest).SingleOrDefault();
    if (appElement != null) { 
        return appElement.Attribute("ProductID").Value; 
    return string.Empty; 


Windows Phone 7 Application Certification Guide

To submit your app to Marketplace for distribution, you will need an App Hub Account. Open one at:

Opening an account is also necessary to developer unlock your Windows Phone 7 hardware.

Tip: Make sure you use an international credit card if opening an account outside of the US.
Tip: If you will use this account for a company, do not use a personal Windows Live ID when creating the account. You don’t want to mix your personal account details with your company’s and after you create the account, you can’t change the Windows Live ID.

For a guide of the Windows Phone 7 registration process, see here.

For a guide of the Windows Phone 7 Marketplace application submission process, see here.

To help teams track their progress in meeting the Windows Phone 7 certification requirements, I’ve created the following guide. I have used this myself when reviewing partners applications prior to submitting to Marketplace. Please see the instructions on the first tab.




Sample Page



This work is licensed under a Creative Commons license.

Windows Phone 7: Detecting Tap and Hold

There are a couple of ways to go about detecting Tap and Hold in Windows Phone 7. This method uses the XNA Touch Gesture recognizer (Microsoft.Xna.Framework.Input.Touch) in a Silverlight application.  The touch gesture recognizer can tell the difference between tap, double-tap,  and hold gestures. Additionally, using the XNA gesture recognizer you don’t need to worry about mistaking a pan/drag for a hold: if you move your finger too much, a tap or hold won’t be recognized. Other solutions involve inferring these events through the use of a timer.  A common application of this is to implement a context menu in your Windows Phone 7 application.

This method handles the ManipulationStarted event to detect the initial tap. In this event, you tell the gesture recognizer which gestures you want to monitor. In this case, tap, double-tap, and hold.  (This is also done in the constructor of the page, to initialize the recognizer.)

Next a 500 ms timer is started. The timer is used to detect when enough ‘hold time’ has elapsed. When the ‘hold time’ threshold is met, the gesture is detected, the gesture recognizer is reset, and the timer is stopped. This is where you would invoke the context menu. (Not implemented here.) A timer is only necessary here for the implementation of a context-menu. You could detect the gesture in the ManipulationCompleted event handler, which fires when the user releases their finger from the screen.

  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.     TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold | GestureType.DoubleTap;
  5. }
  7. System.Windows.Threading.DispatcherTimer dt;
  8. public void StartHoldTimer()
  9. {
  10.     dt = new System.Windows.Threading.DispatcherTimer();
  11.     dt.Interval = new TimeSpan(0, 0, 0, 0, 500);// 500 Milliseconds
  12.     dt.Tick += new EventHandler(dt_Tick);
  13.     dt.Start();
  14. }
  16. int cnt = 0;
  17. void dt_Tick(object sender, EventArgs e)
  18. {
  19.     if (cnt == 3) // 500 ms * 4 == 2 seconds
  20.     {
  21.         cnt = 0;
  22.         GetGesture();
  23.         // disable all events
  24.         TouchPanel.EnabledGestures = GestureType.None;
  25.         // stop the hold timer
  26.         StopHoldTimer();
  27.     }
  28.     cnt++;
  29. }
  31. void StopHoldTimer()
  32. {
  33.     dt.Stop();
  34.     cnt = 0;
  35. }
  37. private void GetGesture()
  38. {
  39.     if (TouchPanel.IsGestureAvailable)
  40.     {
  41.         GestureSample gs = TouchPanel.ReadGesture();
  42.         if (gs.GestureType == GestureType.Hold)
  43.         {
  44.             string gestureString = string.Format("{0}: {1}", gs.GestureType, gs.Position);
  45.             // Tap and Hold detected, report position
  46.             Debug.WriteLine(gestureString);
  47.         }
  48.     }
  49. }
  51. private void PhoneApplicationPage_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
  52. {
  53.     // specify what events the XNA gesture recognizer will look out for
  54.     TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold | GestureType.DoubleTap;
  55.     // start the hold timer
  56.     StartHoldTimer();
  57. }
  59. private void PhoneApplicationPage_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
  60. {
  61.     // disable all events
  62.     TouchPanel.EnabledGestures = GestureType.None;
  63.     // stop the hold timer
  64.     StopHoldTimer();
  65. }



This work is licensed under a Creative Commons license.

Windows Phone 7 : Code Snippet: Enumerate Files in Isolated Storage

This sample code uses the IsolatedStorageFile class to create a few test directories and populates them with files.  Then it recursively enumerates the files and directories, displaying the output in the debug window.

  1. public void EnumerateIsolatedStorageFiles()
  2. {
  3.     try
  4.     {
  5.         // Get an isolated store for this applicaiton and put it into an
  6.         // IsolatedStorageFile object.
  8.         using (IsolatedStorageFile isoStore =
  9.             IsolatedStorageFile.GetUserStoreForApplication())
  10.         {
  11.             // Create sub directories and create files
  12.             // in them to test enumeration
  13.             isoStore.CreateDirectory("A");
  14.             IsolatedStorageFileStream streamA =
  15.                 new IsolatedStorageFileStream(@"A\TestFileA.Txt", FileMode.Create, isoStore);
  17.             isoStore.CreateDirectory("B");
  18.             IsolatedStorageFileStream streamB =
  19.                 new IsolatedStorageFileStream(@"B\TestFileB.Txt", FileMode.Create, isoStore);
  21.             isoStore.CreateDirectory("C");
  22.             IsolatedStorageFileStream streamC =
  23.                 new IsolatedStorageFileStream(@"C\TestFileC.Txt", FileMode.Create, isoStore);
  25.             isoStore.CreateDirectory(@"C\1");
  26.             IsolatedStorageFileStream streamC1 =
  27.                 new IsolatedStorageFileStream(@"C\1\TestFileC1.Txt", FileMode.Create, isoStore);
  29.             isoStore.CreateDirectory(@"D\1\2\3\4\5");
  30.             IsolatedStorageFileStream streamD =
  31.                 new IsolatedStorageFileStream(@"D\1\2\3\4\5\TestFileD.Txt", FileMode.Create, isoStore);
  33.             streamA.Close();
  34.             streamB.Close();
  35.             streamC.Close();
  36.             streamC1.Close();
  37.             streamD.Close();
  39.             // There might be a small delay between when the above code
  40.             // executes and when the files are created in the store.
  41.             // Closing and opening the store in this example ensures that
  42.             // the common language runtime has finished creating the files.
  43.         } // using
  45.         using (IsolatedStorageFile isoStore =
  46.             IsolatedStorageFile.GetUserStoreForApplication())
  47.         {
  48.             // List files in root
  49.             foreach (string file in isoStore.GetFileNames())
  50.             {
  51.                 Debug.WriteLine(file);
  52.             }
  53.             // Recursively enumerate sub-directories and list contents
  54.             GetFiles(isoStore, @"\");
  55.         } // using
  56.     }
  57.     catch (IsolatedStorageException e)
  58.     {
  59.         Debug.WriteLine(e.Message);
  60.     }
  61. }
  63. // Recursively enumerate sub-directories
  64. void GetFiles(IsolatedStorageFile isoStore, string directory)
  65. {
  66.     string[] DirNames;
  67.     if (directory == @"\")
  68.         DirNames = isoStore.GetDirectoryNames();
  69.     else
  70.         DirNames = isoStore.GetDirectoryNames(directory + @"\*");
  72.     foreach (string dir in DirNames)
  73.     {
  74.         string mDir =
  75.             directory == @"\" ? directory + dir : directory + @"\" + dir;
  76.         foreach (string file in isoStore.GetFileNames(mDir + @"\*.*"))
  77.         {
  78.             Debug.WriteLine(file);
  79.         }
  80.         GetFiles(isoStore, mDir);
  81.     }
  82. }




This work is licensed under a Creative Commons license.