First of all please note, that without doing anything custom (i.e. using a URI as an Image.Source), there's already some kind of cache implemented as if you have a Fiddler running next to your app, you'll see that requests are issued once and not each time an item is displayed.
This being said, if you want some kind of persistent cache, you could create a Converter which checks if the desired image is in the App's temporary directory and downloads it if it's not the case.
Here's a way to do it:
public sealed class UriToCachedImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Uri uri = value as Uri;
if (uri == null)
return null;
// Don't let user know those are images, yet keep a unique and consistent name.
string fileName = Path.GetFileName(uri.AbsolutePath);
StorageFile file = null;
try
{
Task<StorageFile> task = ApplicationData.Current.TemporaryFolder.GetFileAsync(fileName).AsTask<StorageFile>();
task.Wait();
file = task.Result;
}
catch (AggregateException ex)
{
if (ex.InnerException is FileNotFoundException)
{
// http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/1eb71a80-c59c-4146-aeb6-fefd69f4b4bb/
}
else
{
throw;
}
}
if (file == null)
{
// File isn't present in cache => download it.
// This creates a file in the app's INetCache
// but we can't retrieve its path or know its name for sure
// hence we're not using this file as our cache file.
Task<StorageFile> streamTask = StorageFile.CreateStreamedFileFromUriAsync(fileName, uri, RandomAccessStreamReference.CreateFromUri(uri)).AsTask<StorageFile>();
streamTask.Wait();
StorageFile storageFile = streamTask.Result;
// Copy file to our temporary directory (can't move as we don't have write access on the initial file).
Task<StorageFile> copyTask = storageFile.CopyAsync(ApplicationData.Current.TemporaryFolder, fileName, NameCollisionOption.ReplaceExisting).AsTask<StorageFile>();
copyTask.Wait();
file = copyTask.Result;
}
Task<IRandomAccessStreamWithContentType> openTask = file.OpenReadAsync().AsTask<IRandomAccessStreamWithContentType>();
openTask.Wait();
IRandomAccessStreamWithContentType randomAccessStream = openTask.Result;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(randomAccessStream);
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Note: This code snippet also illustrates how to call async methods from a synchronous method ;)