Developing for Metro, Part 2 -- Displaying External Images
In my previous post on Metro development, I mentioned that I planned to write more as I delved deeper into this new world.
I am currently working with an app based on Visual Studio's Split Application Metro template. As I've mentioned before, you get a working app, including sample data and images. I am using this template to create an app to track activities and participants in those activities -- their attendance and additional participation.
I was ready to replace the template's sample images with my own, but wanted to load them from my Pictures library rather than embedding them in the app. Pretty simple and straightforward, right? Just add the Pictures Library capability to the manifest and go from there, right? I figured that all I needed to do was to get a URI to the image I wanted to load from the Pictures library and substitute that for the URI of the embedded image and all would be well. Not quite. I figuratively beat my head against this for (literally) a couple of hours before I figured out the correct (or at least a working) method of displaying these images. My Bing-fu wasn't up to the task of finding someone else's solution, so I had to work it out myself.
In the following snippets, ImageSource is a member of the Windows.UI.Xaml.Media namespace, BitmapImage is a member of the Windows.UI.Xaml.Media.Imaging namespace, and IStorageFile is a member of the Windows.Storage namespace.
This is the method of creating a BitmapImage from an embedded image:
ImageSource img = new BitmapImage(new Uri("ms-appx:///Assets/MyImage.png"));
Modifying it to display an image from the Pictures library (using a file:/// URI) didn't work. This, on the other hand, does work for images in the Pictures library:
ImageSource b = new BitmapImage(); IStorageFile i = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(path); ((BitmapImage)b).SetSource(await i.OpenAsync(FileAccessMode.Read));
At the time I didn't understand why it had to be done that way, but I have since had a flash of inspiration that leads me to believe I understand it now. The images embedded in the project are already in memory by the time the app tries to display them (since the app has to be loaded), so the URI method works. However, images in the Pictures library aren't in memory yet, so you have to get them there (the BitmapImage class doesn't load them and neither does the Uri class). That's where the IStorageFile.OpenAsync method comes into play. Of course, I could be completely mistaken about the reasoning here, and someone with more experience may point out that I was doing something wrong that was preventing me from using a URI to create my BitmapImage (I don't think I was -- the URI looked good to me in the debugger, it just wasn't giving me a working BitmapImage).
Now that I have a working method of showing external images, I'm ready to move on to the next step in my project, which is to create editors for activities and participants so that I'm not just displaying static information.