サンプル WPF アプリケーションのクライアントにイメージをキャッシュするにはどうすればよいですか。




wpf page loaded (6)

私はIValueConverterインターフェースを使ってBinding Converterを作成することでこれを解決しました。 私が少なくとも1週間この問題に対する確かな解決策を見つけようとしたことを考えると、私は将来この問題を抱えている人々のために私の解決策を共有するべきだと考えました。

これが私のブログ投稿です: WPFデスクトップアプリケーションのための画像キャッシング

現在HTTP経由で取得されている画像を表示するWPFデスクトップアプリケーションを開発しています。

画像はすでに品質/サイズに対して最適化されていますが、画像が取得されるたびに明らかに待機する必要があります。

毎回ダウンロードされないようにクライアントに画像をキャッシュする方法はありますか?


Answer #1

同じ実行内でキャッシュしようとしているだけの場合は、ローカル辞書がランタイムキャッシュとして機能する可能性があります。

アプリケーションの実行間でキャッシュしようとしている場合、それはトリッキーになります。

これがデスクトップアプリケーションの場合は、キャッシュされた画像をユーザーのアプリケーションデータフォルダーにローカルに保存するだけです。

XBAPアプリケーション(ブラウザ内のWPF)の場合は、セキュリティ上の理由から、ユーザーの分離ストレージにローカルキャッシュを設定することしかできません。


Answer #2

Jeroen van Langenからの返信です。

あなたは行の束を保存することができます

HttpHelperクラスとWebResponse_extension削除しWebResponse_extension

交換する

HttpHelper.GetAndSaveToFile(url, localFile);

によって

WebClient webClient = new WebClient();
    webClient.DownloadFile(url, localFile);

Answer #3

Google経由でここに来る人々のために、私は投稿したJeroen van Langenによってリファクタリングされたオリジナルの実装を(それをバインド可能にするためのIvan Leonenkoからの調整と共に)パッケージ化しました。

ここで詳細を見つけてください - http://floydpink.github.io/CachedImage/


Answer #4

私はあなたのブログを読みました、そしてそれは私にこれをもたらしました(私ははるかに簡単だと思います)概念設定:

あなたが気づくように、私はあなたが共有したあなたのコードのいくつかを再利用しました、それで私は私のものを共有します。

CachedImageという新しいカスタムコントロールを作成します。

public class CachedImage : Image
{
    private string _imageUrl;

    static CachedImage()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CachedImage), new FrameworkPropertyMetadata(typeof(CachedImage)));
    }

    public string ImageUrl
    {
        get
        {
            return _imageUrl;
        }
        set
        {
            if (value != _imageUrl)
            {
                Source = new BitmapImage(new Uri(FileCache.FromUrl(value)));
                _imageUrl = value;
            }
        }
    }
}

次に、FileCacheクラスを作成しました(したがって、イメージだけでなくすべてのキャッシュを制御できます)。

public class FileCache
{
    public static string AppCacheDirectory { get; set; }

    static FileCache()
    {
        // default cache directory, can be changed in de app.xaml.
        AppCacheDirectory = String.Format("{0}/Cache/", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
    }

    public static string FromUrl(string url)
    {
        //Check to see if the directory in AppData has been created 
        if (!Directory.Exists(AppCacheDirectory))
        {
            //Create it 
            Directory.CreateDirectory(AppCacheDirectory);
        }

        //Cast the string into a Uri so we can access the image name without regex 
        var uri = new Uri(url);
        var localFile = String.Format("{0}{1}", AppCacheDirectory, uri.Segments[uri.Segments.Length - 1]);

        if (!File.Exists(localFile))
        {
            HttpHelper.GetAndSaveToFile(url, localFile);
        }

        //The full path of the image on the local computer 
        return localFile;
    }
}

またコンテンツをダウンロードするために私はヘルパークラスを作りました:

public class HttpHelper
{
    public static byte[] Get(string url)
    {
        WebRequest request = HttpWebRequest.Create(url);
        WebResponse response = request.GetResponse();

        return response.ReadToEnd();
    }

    public static void GetAndSaveToFile(string url, string filename)
    {
        using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
        {
            byte[] data = Get(url);
            stream.Write(data, 0, data.Length);
        }
    }
}

HttpHelperは、結果を配列に読み込むためにWebResponseクラスの拡張子を使用します。

public static class WebResponse_extension
{
    public static byte[] ReadToEnd(this WebResponse webresponse)
    {
        Stream responseStream = webresponse.GetResponseStream();

        using (MemoryStream memoryStream = new MemoryStream((int)webresponse.ContentLength))
        {
            responseStream.CopyTo(memoryStream);
            return memoryStream.ToArray();
        }
    }
}

これで完成しました。xamlで使用しましょう

<Grid>
    <local:CachedImage ImageUrl="http://host/image.png" />
</Grid>

それがすべてです、それは再利用可能で堅牢です。

唯一の欠点は、キャッシュディレクトリをクリーンアップするまでイメージが二度とダウンロードされないことです。

イメージがWebから初めてダウンロードされ、キャッシュディレクトリに保存されたとき。 最終的に画像はキャッシュからロードされ、親クラスのソース(Image)に割り当てられます。

親切、Jeroen van Langen。


Answer #5

私はこの質問が非常に古いことを知っていますが、私は最近WPFアプリケーションでキャッシングを使用しなければなりませんでした。

<Image.Source>
  <BitmapImage UriCachePolicy="Revalidate" 
     UriSource="https://farm3.staticflickr.com/2345/2077570455_03891081db.jpg"/>
</Image.Source>

app.configで値を設定して、すべてのアプリがキャッシュにデフォルト値を使用するようにすることもできます。

<system.net>
  <requestCaching defaultPolicyLevel="CacheIfAvailable"/>
</system.net>

RequestCacheLevel値の説明はここにあります。http://msdn.microsoft.com/en-us/library/system.net.cache.requestcachelevel(v=vs.110).aspx

この機能はHTTP / 1.1ヘッダを理解するので、Revalidateを設定すると毎回それをダウンロードすることを避けるためにIf-Modified-Sinceヘッダを使用しますが、それでも画像が変更されたかどうかチェックします。





image