图像源和缓存

我使用以下代码显示来自网络服务器的图像:

 

图像会自动下载,我假设还有一些基于Url的缓存。

我的问题是,当应用程序处于脱机状态时,无法显示缓存的图像。

有没有办法改变缓存行为,以便在没有网络可用时加载图像? 有关缓存的文档指针也非常有用。

默认情况下, BitmapImage自动缓存远程图像。 它最好与CreateOptions="BackgroundCreation"结合使用,以获得最佳性能。

      

这篇MSDN博客文章虽旧但仍然相关,但它列出并解释了所有的CreationOptions并且在大多数模式下缓存都是自动的。

我使用这些选项显示许多带图像的新闻项目,效果很好。 我可以加载文章列表,退出应用程序并将“飞行模式”设置为“开”,然后启动应用程序的新实例,图像仍然会加载。

手动方法

如果你想自己控制缓存并缓存HTTPS资源,那么很少有好的例子……

  • 来自iFixit应用程序的ImgCache
  • 下载和保存图像的值转换器
  • 来自Kawagoe Toolkit的PersistentImageCache (可能需要更新才能使用WP 7.5或8)

我有一个解决方案给你。 它是JetImageLoader ,我是为应用程序创建的,我们需要加载,缓存并显示大量的徽标,图标等。

它可以用作绑定转换器,因此您甚至不应该更改代码! 只需更新您的XAML!

请查看存储库中的示例 ,你会喜欢它;)

特征:

  • 在磁盘上缓存
  • 在内存中缓存
  • 完全异步
  • 可用作绑定转换器或以编程方式从代码中获取
  • 完全开源,分叉并改进它!

这是一个例子:

  

我不认为有这样做的方法,但您可以将图像保存在IsolatedStorage中并使用转换器检查互联网可用性并返回在线或离线url。

快速搜索产生了这可能正是您正在寻找的东西(它与Windows Phone 7兼容,可能不是Windows Phone 8的最佳解决方案)

我的解决方案:(将图像从Web保存到本地存储并将保存的图像绑定到页面)

XAML

        

的DataModel

 public class DataModel_ListOfEvents { public DataModel_ListOfEvents(String img_thumb) { this.Img_Thumb = new NotifyTaskCompletion(JsonCached.ImageFromCache2(img_thumb)); } public NotifyTaskCompletion Img_Thumb { get; private set; } } public sealed class SampleData_ListOfEvents { private static SampleData_ListOfEvents _sampleDataSource = new SampleData_ListOfEvents(); private ObservableCollection _items = new ObservableCollection(); public ObservableCollection Items { get { return this._items; } } } 

魔法

 public class JsonCached { public static async Task 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 : INotifyPropertyChanged { public NotifyTaskCompletion(Task 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 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; } } 

你也可以使用FFImageLoading( https://github.com/molinch/FFImageLoading/

特征

  • Xamarin.iOS(最小iOS 7),Xamarin.Android(最小Android 4),Xamarin.Forms和Windows(WinRT,UWP)支持
  • 可配置的磁盘和内存缓存
  • 类似下载/加载请求的重复数据删除
  • 错误和加载占位符支持
  • 图像可以自动下采样到指定的大小(更少的内存使用)
  • WebP支持
  • 图像加载淡入式动画支持
  • 可以重试图像下载(RetryCount,RetryDelay)
  • 在Android上,默认情况下禁用透明度(可配置)。 节省50%的内存
  • 转换支持
    • BlurredTransformation
    • CircleTransformation,RoundedTransformation,CornersTransformation
    • ColorSpaceTransformation,GrayscaleTransformation,SepiaTransformation
    • FlipTransformation
    • 支持自定义转换(本机平台IT转换实现)

这很简单:

   

这里的示例项目: https : //github.com/molinch/FFImageLoading/tree/master/samples/