.NET Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

SkyDrive Sync on Windows Phone - How Do I Handle External Storage?

09.05.2013
| 2033 views |
  • submit to reddit

In case you missed it, I am running a series that tells you how to build an app that syncs content from your Windows Phone devices directly to SkyDrive. There are two previous installments:

Today I am going to talk about the next topic on the line - how to handle content from external storage.

Obviously, external storage is not something that applies to every Windows Phone 8 device. Although the API supports it, not all devices do. For testing purposes, I am using a Nokia Lumia 825 device, with a 16GB microSD card. It is filled with arbitrary content - some pictures, some text files, a couple of ebooks and videos.

Here comes the interesting part - there are a couple of things that you have to be aware of beforehand:

  • At this point, you can't write content to external storage. This is by design, and you cannot go around this restriction through the publicly available SDK/API.
  • You cannot access built-in media folders. That is also by design. If you see the folders that contain pictures, music or video, that were not created by you - you can't reach them through the API. On the other hand, pictures and screenshots will still be accessible through the standard PhotoChooserTask.
  • You can only read files that have their extension associated with your app. That is, you have to declare in the app manifest which file extensions you want to handle.
  • Some extensions that you might want to registered are already reserved by the OS. This means that you cannot read DOCX, XLSX, MP3 or JPEG files since you cannot directly associate those with your app. For a more complete list please read this MSDN article.

Let's code.

First and foremost, let's dig in the WMAppManifest.xml to make sure that we are declaring some sample file extensions. For now, let's have PDF, RAR and MPG associated with the sync app. To do this, I am going to add the FileTypeAssociation node in the context of Extensions:

<FileTypeAssociation Name="SyncFiles"
                        NavUriFragment="fileToken=%s"
                        TaskID="_default">
     <Logos>
       <Logo Size="small"
             IsRelative="true">Assets/fileIcon.png</Logo>
       <Logo Size="medium"
             IsRelative="true">Assets/fileIcon_69x69.png</Logo>
       <Logo Size="large"
             IsRelative="true">Assets/fileIcon_176x176.png</Logo>
     </Logos>
     <SupportedFileTypes>
       <FileType>.pdf</FileType>
       <FileType>.rar</FileType>
       <FileType>.mpg</FileType>
     </SupportedFileTypes>
</FileTypeAssociation>

NOTE: The Extensions node should be placed right after the Tokens one.

Normally, you would have separate file association nodes created for each of the types you want to handle. However, in this case (for demo purposes), we will use a single file type association with multiple different extensions.

Also, feel free to change the location of the file icons. You can read more about using file associations on Windows Phone here.

Now let's talk about ways to actually select content from the external storage device. For this purpose, I have built a custom control, called FileExplorer. It is a universal solution to file selection, and it allows browsing through the file system both in the isolated storage and the external storage. You can download it by getting the experimental branch of the Coding4Fun Toolkit.

NOTE: Make sure that you have the ID_CAP_REMOVABLE_STORAGE selected as a required capability. Otherwise, an UnauthorizedAccessException will be thrown.


Going back to the prompt where we had to choose the storage target, you are now able to use the FileExplorer control:

else if (returnButton == 1)
{
    // The user decided to use the external storage.

    Dispatcher.BeginInvoke(() =>
        {
            FileExplorer explorer = new FileExplorer();
            explorer.SelectionMode = SelectionMode.File;
            explorer.StorageTarget = StorageTarget.ExternalStorage;
            explorer.OnDismiss += explorer_OnDismiss;

            explorer.Show();
        });
}

When the FileExplorer control is dismissed, an ExternalStorageFile instance is returned in the context of the OnDismiss event handler.


Once the OnDismiss handler is called, I am getting the name and the path of the file as the reference token:

void explorer_OnDismiss(StorageTarget target, object file)
{
    var reference = new FileReference();
    reference.FileType = FileType.ExternalStorage;
    reference.Name = ((ExternalStorageFile)file).Name;
    reference.Token = ((ExternalStorageFile)file).Path;

    FileReferences.Add(reference);
}

The reference is later added to the FileReferences collection, after which it is displayed in the ListBox. 

Congratulations, you are now able to handle external files that will be later transferred to SkyDrive. Since we assume that the SD card is always connected, there is no need to transfer content to the isolated storage as temporary items.