HTML5 Zone is brought to you in partnership with:

Clark is a web evangelist for Microsoft based in Illinois. A Chicago native who can’t spell, Clark as a kid actually made his money building cars, getting grease under his nails. That art of building would later lead him to software development where he drinks the Web Development Kool-Aid. Writing code is what keeps Clark awake at night, while continually working on his craft and rapping with others over a few cold CORS. You can hear Clark muse about software on his podcast Developer Smackdown, or find his family cruising around in a 1968 Camaro SS. Clark is a DZone MVB and is not an employee of DZone and has posted 32 posts at DZone. You can read more from them at their website. View Full User Profile

31 Days of Windows 8 for HTML5 | Day #19 File Picker

11.26.2012
| 3086 views |
  • submit to reddit

 

This article is Day #19 in a series called 31 Days of Windows 8.  Each of the articles in this series will be published for logoboth HTML5/JS and XAML/C#. You can find additional resources, downloads, and source code on our website.

Today, we are going to look at another invaluable tool in Windows 8 development, the File Picker.  There are millions of ways to use the File Picker, but when you boil it down, you’re going to need to get files from the user’s computer for something.  This article will show you how to do it.

Start: package.appxmanifest

As with all of the different mechanisms we’ve used to interact with the user’s system, we need to start with updating our package.appxmanifest file.  Since we are going to be both opening files AND saving files in this article, we need to add both of those Declarations to our file.

For the File Open Picker, you’ll start with a form that looks like this:

image

You’re expected to make one of two choices:

  • Supports any file type.  By checking this box, you are declaring that you could access any file type from your application.
  • Supported file type.  You can also specify which file types you want to open, so if your app only opens Excel files, for example, you could list “.xls” as your file type.

For this demo, you can just select “Supports any file type.” I want to do so, so you can see all the files on your system regardless.  The same process can be done for the File Save Picker, which offers you the same choices, like this:

image

Getting a File from Your User’s Machine

This article is going to build a progressively more complex app for selecting files from a user’s machine.  We’ll start getting just one file, then multiple files, and then multiple files of only a specific file type (.png).  Most of the code for each example is identical, so we’ll focus on what is the “new” code in each step.

For selecting a single file from the user’s hard drive, we are going to start with the FileOpenPicker object.  This is the object that will open the File Picker dialog for the user, help them select one or many files, and return them to us.  It has many options, and we’ll work our way through all of them.  For selecting a single file, of any type, the code starts quite simply:

var _pickers = Windows.Storage.Pickers,
    openPicker = new _pickers.FileOpenPicker();

openPicker.fileTypeFilter.append(".png");
openPicker.suggestedStartLocation = _pickers.PickerLocationId.picturesLibrary

openPicker.pickSingleFileAsync().then(function (file) {
    //do something awesome here
});

You’ll notice that we have to set a fileTypeFilter when we create a FileOpenPicker.  You are not allowed to provide a wildcard, or just ignore the filter.  You have to provide at least one, but you can also provide several, which means you can list 8-10 common file types (especially when you’re looking for images on the user’s device, because they could be PNG, JPG, JPEG, GIF, BMP, etc.) To do so, rather than appending just one fileType we can just replace all of them like so:

openPicker.fileTypeFilter.replaceAll([".png", ".jpg"])

When you run this, your user will see an interface that looks like this:

19-XAML-FilePicker

This is the File Picker interface, and once the user selects a file, it will be returned to your application as a StorageFile, which we have worked with in several of the previous articles in this series.

Next, we might have a good idea as to where the user should start looking for the files they would want to open in your app.  Maybe it’s their Photos collection, or Music.  We can specify one of 8 locations on their computer:

19-XAML-PickerLocationId

So, to get the File Picker to open in one of these locations, you need to add one line of code to your method, so that it looks like this:

openPicker.suggestedStartLocation = _pickers.PickerLocationId.picturesLibrary;

This time the File Picker will launch directly to the location you’ve specified (in my example, it is the Pictures Library):

19-XAML-FilePicker-Location

The last option we can manipulate relates to how the File Picker will display the files.  Simply use the ViewMode property of the FileOpenPicker object, like this:

openPicker.viewMode = _pickers.PickerViewMode.list;

Your options are limited to List or Thumbnail, but they look distinctly different.  Thumbnail ONLY shows a square image representing the file.  List shows an icon as well, but also shows some of the metadata for the files.  Here’s a look at the same folder with each view (click to enlarge):

List

19-XAML-List

Thumbnail

19-XAML-Thumbnail

Retrieving Multiple Files From Your User’s Computer

Sometimes, we want to grab more than one file at a time.  In this case, we can use a different method call on our FileOpenPicker object.  This time, we’ll use the pickMultipleFilesAsync() method.

var _pickers = Windows.Storage.Pickers,
    openPicker = new _pickers.FileOpenPicker();

openPicker.fileTypeFilter.replaceAll([".png", ".jpg"])

openPicker.pickMultipleFilesAsync().then(function (file) {
    //do something awesome here
});

So, more or less, there’s very little difference between selecting one or multiple files from a code perspective.  We do receive a collection of StorageFile objects rather than just one, but that should be expected when we’re enabling multiple files to be selected.

What is different, at least from what I can tell, is HOW the user can select multiple files.

19-XAML-MultipleFileSelection

As you can see from the image above (click to enlarge), not only can we select multiple files, but we can also see that there is a “basket” of sorts at the bottom of the File Picker interface.  This shows a list of the files that the user has selected.  What it also enables, however, is a way for a user to select multiple files at once, from completely different folders.  Your users will be able to select a few files from one folder, and a few files from another, and they’ll all be provided to your application at once, without your user having to make multiple trips to those folders.  This is an absolutely awesome feature that should not be overlooked.

In our final section of this article, let’s look at how we can use the File Picker to also save files to a user’s machine.

Saving a File To Your User’s Hard Drive

One of the related operations we may want to use is to save a file to your user’s machine.  This is different from what we talked about on Day #8 of this series, where we were saving files internal to our application.  In this instance, we are saving a permanent file that will continue to live on the user’s machine, even if our app is uninstalled.  If your files are unusable by other apps, this is likely NOT the way you’d want to store your files.  I generally recommend saving files like this for file types that could be opened by a variety of applications.  To do this, it looks very similar to our FileOpenPicker, but it’s now a FileSavePicker.

The other difference with this situation is that we are writing data to the user’s hard drive.  This means we have all of the other hassles that come with it.  Files can be open already, they can be edited by other apps, or even deleted as we’re working with them.  So we will first launch the File Save Picker to determine where the user wants to save their file (as well as what file type and name they want to give it.  This looks like this:

19-XAML-FileSave

And here’s what the code looks like to make this entire process happen:

var savePicker = new _pickers.FileSavePicker(),
    _pickers = Windows.Storage.Pickers;

var savePicker = new _pickers.FileSavePicker();

savePicker.fileTypeChoices.insert("Plain Text", [".txt"]);
savePicker.fileTypeChoices.insert("31 Days", [".31"]);
savePicker.fileTypeChoices.insert("Excel", [".xlsx"]);

savePicker.suggestedFileName = "31DaysOfWindows8";
savePicker.suggestedStartLocation = _pickers.PickerLocationId.picturesLibrary;

savePicker.pickSaveFileAsync().then(function (file) {
    //yea do awesome here
})

In this case, you can see that the beginning of our code sample doesn’t look that different.  Instead of filters, we can add FileTypeChoices which function as the different formats our user might want to save their file.  The choices I’ve included don’t really make much sense together, but it helps to illustrate that you can specify any file types (or types) in this list. I also added a suggestedFileName to help guide the user as to what we think the file should be called.  This is all at your full control.

In addition, once the user has selected a location and name for their file, we’re not done.  If they actually returned those values to use, our next step is to actually write the file to the drive itself.  Let’s crawl into the promise and see just how we would save it off.

var _pickers = Windows.Storage.Pickers,
    _fileManager = Windows.Storage.CachedFileManager,
    _fileIO = Windows.Storage.FileIO,
    _updateStatus = Windows.Storage.Provider.FileUpdateStatus;

savePicker.pickSaveFileAsync().then(function (file) {
    if (file) {
        _fileManager.deferUpdates(file);
        _fileIO.writeTextAsync(file, "file contents").done(function () {
            _fileManager.completeUpdatesAsync(file).done(function (updateStatus) {
                if (updateStatus === _updateStatus.complete) {
                    //saved
                } else {
                    //opps
                }
            });
        });
    } else {
        //user cancelled
    }
});

Inside our if statement, we first check to make sure we actually received a file. We then use the deferUpdates() method to prevent any additional edits to the file that we’re working with.  They will be “deferred” until after our operation is complete.  Next, we write the contents of our file.  Finally, we commit those changes using the completeUpdatesAsync() method.  This is where all of the work is actually completed.

You’ll find that if the file already exists, you’ll also get prompted with a “Replace the existing file?” dialog box.

19-XAML-ReplaceDialog

Ultimately, that’s all it takes to save a simple file to the user’s system.  For more complex operations and file types, you’re going to want to explore the FileIO class.  You can read more about that on MSDN.

Selecting a Folder on the User’s Machine

The last topic I want to cover in this article is also very related to the others: selecting a folder from the user’s machine instead of a specific file.  This is great for allowing the user to choose a default save location for the future, or perhaps a place for you to look for files in the future.  What’s great about this process is that once the user has selected a folder, we can save it as our default folder, and we are granted explicit rights to read and write to/from this folder in the future without having to request future access.  Here’s how we do it.

var _pickers = Windows.Storage.Pickers,
    _fileManager = Windows.Storage.CachedFileManager,
    _fileIO = Windows.Storage.FileIO,
    _updateStatus = Windows.Storage.Provider.FileUpdateStatus;

var folderPicker = new _pickers.FolderPicker(),
    accessCache = Windows.Storage.AccessCache;

folderPicker.fileTypeFilter.replaceAll([".txt", ".31"]);

folderPicker.pickSingleFolderAsync().then(function (folder) {
    if (folder) {
        accessCache.StorageApplicationPermissions.futureAccessList.addOrReplace
            ("PickedFolderToken", folder);
    }
});

As you can see, all of this code look very familiar.  However, if we confirm that an actual folder was returned to us, we can save this to the StorageApplicationPermissions.futureAccessList as a place we have been granted permission to use.  Saving it this way, and referring to it in the future will limit the number of times you have to ask your user for permission to save a file to their system.

Summary

Today, we looked at several different ways to help our users interact with the files that live on their machine.  We saw how to open single and multiple files, save files back to the hard drive, and even select default save locations for future use.  You’ll likely find yourself using these methods over and over in your apps, so this is an important lesson to learn.

If you would like to download the sample code that was discussed in this article, click the icon below:

downloadHTML

Tomorrow, we’re going to take a look at another common feature you’re likely to run into: Printing.  We’ll look at how to communicate with a user’s printers, as well as how we register with the system to make printing even easier.  See you then!

downloadTheTools

Published at DZone with permission of Clark Sell, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)