I was recently working on a Windows Phone 8 app and had a requirement to download and display images from the web in the app. This seemed like a fairly straightforward task but I couldn't quite find what I was looking for when I did some research. The easiest solution would have been to create an Image control, drop it on the page, and set the URL as the Source of the image. The problem with this approach is that every time the image is displayed, it will make an HTTP request and download the image data again. Clearly this isn't optimal, and I needed to develop a solution where I could download the image, save it locally and then display it again from disk as necessary.

For this blog post I am going to create a simple "contact" type of app. When the app first launches there will be a list of all contacts along with a placeholder image for the contacts photo. When each contact displays the app will see that there is no image data available and it will make an HTTP request to retrieve the image. After the image has been retrieved it will replace the placeholder image that was displayed when the app first launched. If you'd like to skip right to the sample code it can be found here.

Downloading The Image

Since we won't just be setting the Source property of our Image control, we will need to download the image manually. For this app I have decided to use the Microsoft HTTP Client Libraries. The Microsoft HTTP Client Libraries are a set of classes that make it easy to interact with HTTP and REST based services. You add them to your project through the NuGet package manager. (This post isn't about NuGet, but if you aren't familiar with it you can find more information here.

After adding this package we are now ready to implement the code to retrieve the image. The sample app lists contacts and displays a photo for each one. I added a static method to my App.xaml.cs file to retrieve the photo data. It looks like this:

public static async Task LoadContactPhoto(ContactViewModel contact) 
{ 
 using (var client = new HttpClient()) 
 { 
 var requestMessage = new HttpRequestMessage(HttpMethod.Get, contact.ImageUrl); 
 var responseMessage = await client.SendAsync((requestMessage)); 
 var responseData = await responseMessage.Content.ReadAsByteArrayAsync(); 
 contact.ImageData = responseData; 
 } 
} 

The method is asynchronous so that we can offload the retrieval of the image to a background thread and not block the UI. In this method we create an instance of an HttpClient, which does all the hard work so that you don't have to. We then create an HttpRequestMessage specifying that we are doing a GET and passing in the URL to the image we want to retrieve. We then call the SendAsync method on our HttpClient passing in ourHttpRequestMessage. This returns an HttpResponseMessage instance that contains the actual response we got from our call. The last step in this process is to read our response message content into a byte array so we can then turn that into an image we can display in our app.

Converting the Byte Array to an Image

Now that we have our image data as a byte array, we still have to convert it into something our app can display to the user. Reading a byte array into memory and converting it into an image can be a somewhat expensive operation and not something we want to do very often. As with the actual retrieval of the image data we will offload the conversion to a background thread so as to not block the UI thread. In the sample app, myContactViewModel class has an ImageData and a Photo property. In order to set the image I set the ImageData property with my byte array from the HTTP request. The setter for ImageData calls an asynchronous method to convert the byte array into an ImageSource which is something that the app can display to the user. The method to convert the bye array into an ImageSource looks like this:

private async Task LoadImageAsync() 
{ 
 using (var ms = new MemoryStream(ImageData)) 
 { 
 var image = new BitmapImage(); 
 image.SetSource(ms); 
 Photo = image; 
 } 
}

In this method we convert our byte array (ImageData) to a MemoryStream. We then create a new BitmapImage and set its source to our MemoryStream. We then set the Photo property of our ViewModel to the BitmapImagewe just created (BitmapImage is a subclass of ImageSource) and because our view model implements the INotifyPropertyChanged interface, our image shows up in the app.

As you can see, downloading an image once and displaying it in your app is very easy to do. Of course with this example we only keep a copy of the image in memory so the next time the app runs we would have to download it again. In reality you would probably want to keep the image in a more persistent store such as SQLite or even in local storage. In a future post I will cover storing the image in a SQLite database on the device.