次のコードを使用して、Webサーバーからの画像を表示します。
<Image Source="{Binding Url}" />
画像は自動的にダウンロードされ、URLに基づいたキャッシュもあると思います。
私の問題は、アプリがオフラインのとき、おそらくキャッシュされた画像が表示されないことです。
利用可能なネットワークがないときに画像も読み込まれるように、キャッシュ動作を変更する方法はありますか?キャッシングに関するドキュメントへのポインタも非常に役立ちます。
BitmapImage
は、デフォルトでリモート画像を自動的にキャッシュします。最高のパフォーマンスを得るには、CreateOptions="BackgroundCreation"
と組み合わせて使用するのが最適です。
<Image Height="100" Width="100" Margin="12,0,9,0">
<Image.Source>
<BitmapImage UriSource="{Binding ImgURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
このMSDNブログ投稿 、古いがまだ関連性があり、すべてのCreationOptions
をリストして説明し、ほとんどのモードでキャッシュが自動化されています。
私はこれらのオプションを使用して、画像付きの多くのニュースアイテムを表示し、うまく機能します。記事のリストを読み込んでアプリを終了し、機内モードをオンにしてから、アプリの新しいインスタンスを起動しても画像は読み込まれます。
手動アプローチ
キャッシュを自分で制御し、HTTPSリソースをキャッシュしたい場合は、いくつかの良い例があります...
私はあなたのための解決策を持っています。 JetImageLoader です。大量のロゴやアイコンなどを読み込んでキャッシュし、表示する必要があるアプリケーション用に作成しました。
バインディングコンバーターとして使用できるので、コードを変更することすらしないでください! XAMLを更新するだけです!
どうぞ、チェックしてください リポジトリ内のサンプル 、あなたはそれを気に入るはずです;)
機能:
次に例を示します。
<Image Source="{Binding ImageUrl, Converter={StaticResource MyAppJetImageLoaderConverter}}"/>
それを行う方法はないと思いますが、IsolatedStorageに画像を保存し、インターネットの可用性をチェックしてオンラインまたはオフラインのURLを返すコンバーターを使用することができます。
クイック検索でこれが得られました これはまさにあなたが探しているものかもしれません(Windows Phone 7と互換性があり、Windows Phone 8に最適なソリューションではない可能性があります)
FFImageLoadingを使用することもできます( https://github.com/molinch/FFImageLoading/ )
それは同じくらい簡単です:
<ff:MvxCachedImage Name="image"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
LoadingPlaceholder="loading.png"
ErrorPlaceholder="error.png"
RetryCount="3"
RetryDelay="250"
DownsampleHeight="300"
ImagePath="http://lorempixel.com/output/city-q-c-600-600-5.jpg">
</ff: MvxCachedImage >
ここのサンプルプロジェクト: https://github.com/molinch/FFImageLoading/tree/master/samples/
私の解決策:(画像をWebからローカルストレージに保存し、保存した画像をページにバインドする)
XAML
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<!--Some code removed-->
<Image Source="{Binding Img_Thumb.Result}" />
</DataTemplate>
</ListView.ItemTemplate>
データ・モデル
public class DataModel_ListOfEvents
{
public DataModel_ListOfEvents(String img_thumb)
{
this.Img_Thumb = new NotifyTaskCompletion<string>(JsonCached.ImageFromCache2(img_thumb));
}
public NotifyTaskCompletion<string> Img_Thumb { get; private set; }
}
public sealed class SampleData_ListOfEvents
{
private static SampleData_ListOfEvents _sampleDataSource = new SampleData_ListOfEvents();
private ObservableCollection<DataModel_ListOfEvents> _items = new ObservableCollection<DataModel_ListOfEvents>();
public ObservableCollection<DataModel_ListOfEvents> Items { get { return this._items; } }
}
魔法
public class JsonCached
{
public static async Task<string> ImageFromCache2(string path)
{
int ru = path.IndexOf(".ru") + 4;// TODO: .com .net .org
string new_path = path.Substring(ru).Replace("/", "\\");
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
try
{
Stream p = await localFolder.OpenStreamForReadAsync(new_path);
p.Dispose();
System.Diagnostics.Debug.WriteLine("From cache");
return localFolder.Path + "\\" + new_path;
}
catch (FileNotFoundException)
{
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("{0}", e.Message);
}
StorageFile storageFile = await localFolder.CreateFileAsync(new_path, CreationCollisionOption.OpenIfExists);
Uri Website = new Uri(path);
HttpClient http = new HttpClient();
// TODO: Check connection. Return message on fail.
System.Diagnostics.Debug.WriteLine("Downloading started");
byte[] image_from_web_as_bytes = await http.GetByteArrayAsync(Website);
MakeFolders(localFolder, path.Substring(ru));
Stream outputStream = await storageFile.OpenStreamForWriteAsync();
outputStream.Write(image_from_web_as_bytes, 0, image_from_web_as_bytes.Length);
outputStream.Position = 0;
System.Diagnostics.Debug.WriteLine("Write file done {0}", outputStream.Length);
outputStream.Dispose();
return localFolder.Path + "\\" + new_path;
}
private static async void MakeFolders(StorageFolder localFolder, string path)
{
//pics/thumbnail/050/197/50197442.jpg
int slash = path.IndexOf("/");
if (slash <= 0) // -1 Not found
return;
string new_path = path.Substring(0, slash);
StorageFolder opened_folder = await localFolder.CreateFolderAsync(new_path, CreationCollisionOption.OpenIfExists);
string very_new_path = path.Remove(0, new_path.Length + 1);
MakeFolders(opened_folder, very_new_path);
}
}
NotifyTaskCompletion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace App2.NotifyTask
{
public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
{
public NotifyTaskCompletion(Task<TResult> task)
{
Task = task;
if (!task.IsCompleted)
{
var _ = WatchTaskAsync(task);
}
}
private async Task WatchTaskAsync(Task task)
{
try
{
await task;
}
catch
{
}
var propertyChanged = PropertyChanged;
if (propertyChanged == null)
return;
propertyChanged(this, new PropertyChangedEventArgs("Status"));
propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted"));
if (task.IsCanceled)
{
propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
}
else if (task.IsFaulted)
{
propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
propertyChanged(this, new PropertyChangedEventArgs("Exception"));
propertyChanged(this,
new PropertyChangedEventArgs("InnerException"));
propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
}
else
{
propertyChanged(this,
new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("Result"));
}
}
public Task<TResult> Task { get; private set; }
public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); } }
public TaskStatus Status { get { return Task.Status; } }
public bool IsCompleted { get { return Task.IsCompleted; } }
public bool IsNotCompleted { get { return !Task.IsCompleted; } }
public bool IsSuccessfullyCompleted { get { return Task.Status == TaskStatus.RanToCompletion; } }
public bool IsCanceled { get { return Task.IsCanceled; } }
public bool IsFaulted { get { return Task.IsFaulted; } }
public AggregateException Exception { get { return Task.Exception; } }
public Exception InnerException { get { return (Exception == null) ? null : Exception.InnerException; } }
public string ErrorMessage { get { return (InnerException == null) ? null : InnerException.Message; } }
public event PropertyChangedEventHandler PropertyChanged;
}
}