Wintellect Blogs

Handling File/Folder Pickers and Web Authentication Broker in Universal Windows Store and Windows Phone Apps

27 Jul , 2014  

I was very excited when Microsoft announced Universal Apps for Windows Store and Windows Phone Apps. One reason is that I can use my existing C#/CLR/WinRT skill set to now build phone apps. Another reason is because it means my Windows Runtime via C# book now has a new audience. In fact, the book’s content is entirely applicable for Windows Phone 8.1 developers except for the few differences mentioned in a document you can download from the Wintellect website by selecting “For Windows Phone Developers.” I’ve already converted all the book’s code samples to universal apps and I have them running on both Windows and Windows Phone. You can download the code from the Wintellect website by selecting “Source Code.”

Of course, the main purpose to use universal apps is because it allows you to create different user interfaces for Windows Store, Windows Phone, and XBOX apps while sharing your business logic between them. Specifically, universal apps allow your common business logic to exist in a shared project while your platform-specific user interface code resides in platform-specific projects. However, while I was converting my book’s samples to universal apps, the toughest thing I ran into is the difference between how Windows Store and Windows Phone apps handle file pickers, folder pickers, and the web authentication broker. Due to phone devices typically having small amounts of RAM (some with just 512MB), after your app displays a picker or web authentication broker, the system suspends your app and possibly terminates it. This frees up memory giving the user a better experience with the picker/broker. Then after the user has completed using the picker/broker, the system activates your app again calling you App class’ virtualOnActivated method. You must override this method to get the result of the user’s interaction with the picker/broker. For Windows Store apps, your app just continues to run while the user is interacting with a picker/broker. These two models are pretty different from one another and the code you must write to handle these two models is pretty different.

I didn’t like this and so I set out on a mission to come up with simple and reusable helper classes allowing me to write code once having it work for both Windows Store and Windows Phone apps. In addition, my classes simplify the code necessary to handle the continuation. So, even if you only care about Windows Phone apps, my helper classes simplify the code necessary to work with a picker/broker. With my helper classes the code to show a picker looks like this:

// Creates, initializes, and shows a picker (works for Windows Store and Windows Phone apps)
private void GetFile(Object sender, RoutedEventArgs e) {
   // Create and initialize a picker
   FileOpenPicker picker = new FileOpenPicker {
      SuggestedStartLocation = PickerLocationId.Desktop,
      ViewMode = PickerViewMode.List,
      FileTypeFilter = { ".png", ".jpg" },
      CommitButtonText = "Upload"
   };

   // If you need any continuation data, add it like this:
   picker.GetContinuationData().Add("Key1", "Value1");
   picker.GetContinuationData().Add("Key2", "Value2");

   // Display picker indicating method to invoke after user's selection
   picker.PickSingleFileAndContinue(GetFileContinuation);
}

In the code above, the GetContinuationData method is an extension method available via my helper class. This method allows you to add, remove or examine continuation data that you can associate with the picker. The PickSingleFileAndContinue method is another of my extension methods. It displays the displays the picker and indicates which method should be invoked when the user is finished using the picker. The code in this callback method should look similar to what I show below:

// Called after user performs selection with the picker
private void GetFileContinuation(FileOpenPickerContinuationEventArgs args) {
   if (args.Files.Count == 0) return; // User canceled the picker

   // If you need continuation data, access as you normally would:
   Object value1 = args.ContinuationData["Key1"];
   Object value2 = args.ContinuationData["Key2"];

   // Get the user-selected file
   StorageFile file = args.Files[0];
   // TODO: Perform operation with the user-selected file…...
}

In a Windows Store app, my PickSingleFileAndContinue extension method invokes your GetFileContinuation method after the user dismisses the picker. In a Windows Phone app, Windows will activate the app calling your App class’ OnActivated method. Your code must override this method and call another extension method (OnActivatedForContinuation) provided by my helper class. My method will, in turn, invoke your GetFileContinuation callback method. My OnActivatedForContinuation method does nothing when called in a Windows Store app;. Here’s what your App’s OnActivated method should look like:

// Override this method in your App class
protected override void OnActivated(IActivatedEventArgs args) {
   args.OnActivatedForContinuation(((Frame)Window.Current.Content).Content);
   base.OnActivated(args);
}

The pattern I show in this post works for all the file and folder pickers. I have a similar pattern that works with the web authentication broker. I encourage you to download my book’s sample code to get my helper classes and to see examples of how to use them with the file pickers and the web authentication broker.
While working on this code and understanding the motivation for Microsoft’s Windows Phone team to implement the pickers/broker with this continuation mechanism, I came to a very important realization: you must design Windows Store and Windows Phone apps to conserve as much memory as possible. The small amount of RAM on phones is what led Microsoft to design the pickers/broker with this continuation model. And, as tablets and portable computers become more commonplace over desktop PCs, the machines our apps run on are likely to have less memory than what we as developers have become used to. This requires that we design our apps to conserve as much memory as possible. Let me give you an example as to what this now means for me.

In the past, I might design a Windows Store app so that every time the user launched my app due to a file association, I’d add a new page to my frame allowing the user to work on this new file. But, I’d also allow the user to navigate backwards and forwards through all the files they had sent to my app. The problem with this design is that my app might have multiple files in memory simultaneously. Now, realizing how limited memory is, I’d design my app differently. Whenever the user launched my app via a new file, I’d save the current file and allow its content to be freed from memory making room for the new file’s data. This way, my app would never be working on more than one file at a time conserving memory and probably simplifying the user experience too.