まず第一に、カスタム (つまり、URI を Image.Source として使用) を行わなくても、アプリの横で Fiddler を実行しているかのように、何らかの種類のキャッシュが既に実装されていることに注意してください。リクエストが発行されていることがわかります。アイテムが表示されるたびにではなく、一度だけ。
そうは言っても、ある種の永続的なキャッシュが必要な場合は、必要な画像がアプリの一時ディレクトリにあるかどうかを確認し、そうでない場合はダウンロードする Converter を作成できます。
これを行う方法は次のとおりです。
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();
}
}
注: このコード スニペットは、同期メソッドから非同期メソッドを呼び出す方法も示しています ;)