0

これは私の以前の質問の延長です。メトロ アプリはトゥームストーン化のために画像をキャッシュする方法を教えてください。

私が見つけた解決策は HttpClient を使用することですが、これにより、Web サーバー上のファイルごとに不要な 2 番目のヒットが発生します。

Image/ImageSource から既存のイメージ/ストリームを保存する方法はありますか (ImageOpened イベントを使用して利用可能であることを確認します)。

これは CP から大きな変更が加えられた領域であるため、ソリューションは現在の RP API で動作する必要があります。

4

3 に答える 3

2

まず第一に、カスタム (つまり、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();
    }
}

注: このコード スニペットは、同期メソッドから非同期メソッドを呼び出す方法も示しています ;)

于 2012-11-27T17:34:44.133 に答える
0

FFImageLoading ( https://github.com/molinch/FFImageLoading/ ) を使用するか、そのソースを参照して実装方法を確認することもできます ( https://github.com/molinch/FFImageLoading/tree/master/FFImageLoading.Windows ) 。

特徴

  • Xamarin.iOS (最小 iOS 7)、Xamarin.Android (最小 Android 4)、Xamarin.Forms、および Windows (WinRT、UWP) のサポート
  • 構成可能なディスクとメモリのキャッシュ
  • 同様のダウンロード/ロード要求の重複排除
  • エラーとプレースホルダーの読み込みのサポート
  • 画像は指定したサイズに自動的にダウンサンプリングできます (メモリ使用量が少なくなります)
  • WebP サポート
  • 画像の読み込み フェードイン アニメーションのサポート
  • 画像のダウンロードを再試行できます (RetryCount、RetryDelay)
  • Android では、透過性はデフォルトで無効になっています (構成可能)。メモリの 50% を節約
  • 変換のサポート
    • ぼやけた変換
    • CircleTransformation、RoundedTransformation、CornersTransformation
    • ColorSpaceTransformation、GrayscaleTransformation、SepiaTransformation
    • FlipTransformation
    • カスタム変換をサポート (ネイティブ プラットフォームの ITransformation 実装)

次のように簡単です。

<ff:FFImage Name="image"
    VerticalAlignment="Stretch" 
    HorizontalAlignment="Stretch"
    LoadingPlaceholder="loading.png"
    ErrorPlaceholder="error.png"
    CacheDuration="30"
    RetryCount="3"
    RetryDelay="250"
    DownsampleHeight="300"
    Source="http://lorempixel.com/output/city-q-c-600-600-5.jpg">
</ff:FFImage>

サンプル プロジェクトはこちら: https://github.com/molinch/FFImageLoading/tree/master/samples/Simple.WinPhone.Sample

于 2015-11-24T17:19:23.373 に答える
0

ImageOpened イベントから必要なことを実行する方法がわかりませんが、代わりに機能するモデルを見つけました。

画像 uri を画像ソースにバインドし、メトロに画像をダウンロードさせる代わりに、画像のタグにバインドし、データ バインディングが完了したら、xaml の各画像をループし、画像を RandomAccessStream としてダウンロードして、ストリームを保存します。 Image Source をストリームから作成された BitmapImage に設定します。

RandomAccessStreamReference rasf = RandomAccessStreamReference.CreateFromUri(new Uri(MyImage.Tag as string));
BitmapImage bitmapImage = new BitmapImage();
var ras = await rasf.OpenReadAsync();
bitmapImage.SetSource(ras);
MyImage.Source = bitmapImage;

また、コードをコンバーターとビュー モデル プロパティに配置してプロセスを自動化することも調査しましたが、非同期呼び出しのため、これらのいずれも可能ではありませんでした。

于 2012-06-20T15:04:54.623 に答える