博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【WP8】图片缓存控件
阅读量:5957 次
发布时间:2019-06-19

本文共 19296 字,大约阅读时间需要 64 分钟。

在做图片相关的应用的时候,经常需要用大图片的缓存,默认的Image控件不支持缓存的支持,本文自定义一个支持图片缓存的控件

  当图片的地址是网络图片时候

    根据Url判断该图片是否存在本地,如果存在,则直接从本地读取,如果不存在,则通过Http请求下载该图片,保存到本地,然后读取到Image控件中

  当图片为本地地址的时候,直接从本地读取,设置到Image控件中

 

1、在定义可缓存图片控件之前,先封装一下文件存储的帮助类

using System;using System.IO;using System.IO.IsolatedStorage;using System.Text;using System.Threading.Tasks;using System.Windows;using Windows.ApplicationModel;using Windows.Storage;using Newtonsoft.Json;using XTuOne.Common.Helpers;namespace XTuOne.Utility.Helpers{    public class StorageHelper : IStorageHelper    {        #region 单例        public static IStorageHelper Instance { get; private set; }        public static object LockObject;        static StorageHelper()        {            Instance = new StorageHelper();            LockObject = new object();        }        private StorageHelper()        {        }        #endregion                #region 同步读写方法        public Stream ReadFile(string filePath)        {            lock (LockObject)            {                using (var sf = IsolatedStorageFile.GetUserStoreForApplication())                {                    if (!sf.FileExists(filePath))                    {                        throw new FileNotFoundException(string.Format("没有找到文件:{0}", filePath));                    }                    using (var fs = sf.OpenFile(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))                    {                        var stream = new MemoryStream();                        fs.CopyTo(stream);                        stream.Seek(0, SeekOrigin.Begin);                        return stream;                    }                }            }        }        public string CreateFile(Stream stream, string filePath, bool replace = false)        {            lock (LockObject)            {                using (var sf = IsolatedStorageFile.GetUserStoreForApplication())                {                    var directory = Path.GetDirectoryName(filePath);                    if (directory != null && !sf.DirectoryExists(directory))                    {                        //如果目录不存在,则创建                        sf.CreateDirectory(directory);                    }                    if (FileExist(filePath))                    {                        if (!replace)                        {                            return filePath;                        }                        sf.DeleteFile(filePath);                    }                    //如果不存在或者存在且替换                    using (var fs = sf.CreateFile(filePath))                    {                        stream.CopyTo(fs);                    }                }            }            return filePath;        }        public string CreateFile(byte[] data, string filePath, bool replace = false)        {            lock (LockObject)            {                using (var sf = IsolatedStorageFile.GetUserStoreForApplication())                {                    var directory = Path.GetDirectoryName(filePath);                    if (directory != null && !sf.DirectoryExists(directory))                    {                        //如果目录不存在,则创建                        sf.CreateDirectory(directory);                    }                    if (FileExist(filePath))                    {                        if (!replace)                        {                            return filePath;                        }                        sf.DeleteFile(filePath);                    }                    //如果不存在或者存在且替换                    using (var fs = new IsolatedStorageFileStream(filePath, FileMode.OpenOrCreate, sf))                    {                        fs.Write(data, 0, data.Length);                    }                }            }            return filePath;        }        public string ReadAllText(string fileName)        {            using (var reader = new StreamReader(ReadFile(fileName)))            {                return reader.ReadToEnd();            }        }        public string WriteAllText(string fileName, string text, bool replace)        {            return CreateFile(Encoding.UTF8.GetBytes(text), fileName, replace);        }        #endregion        #region 异步读写方法        public async Task
ReadFileAsync(string filePath) { var storageFile = await GetStorageFileAsync(filePath); return await storageFile.OpenStreamForReadAsync(); } public async Task
CreateFileAsync(Stream stream, string filePath, bool replace = false) { var storageFile = await GetStorageFileAsync(filePath); if (storageFile != null) { if (FileExist(filePath)) { if (replace) { //替换先删除 await storageFile.DeleteAsync(StorageDeleteOption.PermanentDelete); } else { return filePath; } } storageFile = await GetStorageFileAsync(filePath); var destStream = await storageFile.OpenStreamForWriteAsync(); await stream.CopyToAsync(destStream); } return filePath; } public async Task
CreateFileAsync(byte[] data, string filePath, bool replace = false) { var storageFile = await GetStorageFileAsync(filePath); if (storageFile != null) { if (FileExist(filePath)) { if (replace) { //替换先删除 await storageFile.DeleteAsync(StorageDeleteOption.PermanentDelete); } else { return filePath; } } storageFile = await GetStorageFileAsync(filePath); var destStream = await storageFile.OpenStreamForWriteAsync(); await destStream.WriteAsync(data, 0, data.Length); } return filePath; } public async Task
ReadAllTextAsync(string fileName) { using (var reader = new StreamReader(await ReadFileAsync(fileName))) { return await reader.ReadToEndAsync(); } } public async Task
WriteAllTextAsync(string fileName, string text, bool replace) { return await CreateFileAsync(Encoding.UTF8.GetBytes(text), fileName, replace); } #endregion #region 普通方法:判断文件(文件夹)存在,创建(删除)文件夹,获取文件(文件夹) public bool FileExist(string fileName) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { return sf.FileExists(fileName); } } public bool DirectoryExist(string directory) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { return sf.DirectoryExists(directory); } } public void DeleteFile(string fileName) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { if (sf.FileExists(fileName)) { sf.DeleteFile(fileName); } } } public void CreateDirectory(string directory) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { if (sf.DirectoryExists(directory)) { sf.DeleteDirectory(directory); } } } public void DeleteDirectory(string directory, bool isDeleteAll) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { if (sf.DirectoryExists(directory)) { if (isDeleteAll) { var files = GetFiles(directory); foreach (var file in files) { DeleteFile(file); } var directories = GetDirectories(directory); foreach (var s in directories) { DeleteDirectory(s, true); } } sf.DeleteDirectory(directory); } } } public string[] GetFiles(string directory) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { return sf.GetFileNames(directory); } } ///
/// 获取本地文件夹中的文件 /// public string[] GetDirectories(string directory) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { return sf.GetDirectoryNames(directory); } } #endregion #region 拷贝文件(从安装包到本地) ///
/// 从安装包拷贝文件到本地 /// public async Task CopyPackageFileToLocalAsync(string source, string target = null, bool replace = false) { using (var stream = GetResourceStream(source)) { await CreateFileAsync(stream, target ?? source, replace); } } ///
/// 从安装包拷贝路径到本地 /// public async Task CopyPackageFolderToLocalAsync(string source, string target = null, bool replace = false) { target = target ?? source; var packagePath = Package.Current.InstalledLocation; var folder = await GetStorageFolderAsync(packagePath, source); //拷贝文件 var files = await folder.GetFilesAsync(); foreach (var storageFile in files) { var fileName = storageFile.Name; using (var stream = await storageFile.OpenStreamForReadAsync()) { await CreateFileAsync(stream, target + fileName, replace); } } //拷贝子文件夹(递归) var folders = await folder.GetFoldersAsync(); foreach (var storageFolder in folders) { await CopyPackageFolderToLocalAsync(source + storageFolder.Name + "/", target + storageFolder.Name + "/", replace); } } #endregion #region 从安装包(安装路径)中读取(同步) public Stream GetResourceStream(string file) { //引用安装路径的文件的时候不以'/'开头 file = file.TrimStart('/'); return Application.GetResourceStream(new Uri(file, UriKind.Relative)).Stream; } #endregion #region 序列化 public void Serialize
(string fileName, T obj, bool replace) { var json = JsonConvert.SerializeObject(obj); WriteAllText(fileName, json, replace); } T IStorageHelper.DeSerialize
(string fileName) { var json = ReadAllText(fileName); return JsonConvert.DeserializeObject
(json); } public async Task SerializeAsync
(string fileName, T obj, bool replace) { var json = JsonConvert.SerializeObject(obj); await WriteAllTextAsync(fileName, json, replace); } public async Task
DeSerializeAsync
(string fileName) { var json = await ReadAllTextAsync(fileName); return JsonConvert.DeserializeObject
(json); } #endregion #region 辅助方法 ///
/// 根据路劲获取StorageFolder /// private async Task
GetStorageFolderAsync(StorageFolder folder, string directory) { var directories = directory.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); foreach (var s in directories) { folder = await folder.CreateFolderAsync(s, CreationCollisionOption.OpenIfExists); } return folder; } ///
/// 根据文件名异步获取本地文件夹StorageFolder(如果路径不存在,则创建路径) /// private async static Task
GetStorageFolderAsync(string filePath) { var localFolder = ApplicationData.Current.LocalFolder; var directory = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(directory)) { var directories = directory.Split(new[] { '\\', '/'}, StringSplitOptions.RemoveEmptyEntries); foreach (var s in directories) { localFolder = await localFolder.CreateFolderAsync(s, CreationCollisionOption.OpenIfExists); } } return localFolder; } ///
/// 根据路径得到StoreageFile /// private async static Task
GetStorageFileAsync(string filePath) { var folder = await GetStorageFolderAsync(filePath); var fileName = Path.GetFileName(filePath); if (fileName != null) { return await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists); } return null; } #endregion }}

图片的写入和读取都使用了线程锁,在最后说明

注意:上面的异步方法是线程不安全的,在多线程的情况下,当文件被一个线程写入的时候,另一个线程调用读的方法会抛出异常 Access Deny,访问被阻止

 

 

实现了StorageHelper,下面是CacheableImage的实现,支持占位图片,加载失败图片,配置保存路径

2、自定义可缓存图片控件的实现

CacheableImage.xaml

 

using System;using System.IO;using System.Net;using System.Threading.Tasks;using System.Windows;using System.Windows.Media;using System.Windows.Media.Imaging;using XTuOne.Utility.Helpers;namespace XTuOne.Controls{    ///     /// 支持本地缓存的图片空间    ///     public partial class CacheableImage    {        public CacheableImage()        {            InitializeComponent();        }        public static readonly DependencyProperty CachedDirectoryProperty = DependencyProperty.Register(            "CachedDirectory", typeof (string), typeof (CacheableImage), new PropertyMetadata("/ImageCached/"));        public static readonly DependencyProperty FaildImageUrlProperty = DependencyProperty.Register(            "FaildImageUrl", typeof(Uri), typeof(CacheableImage), new PropertyMetadata(default(string)));        public static readonly DependencyProperty LoadingImageUrlProperty = DependencyProperty.Register(            "LoadingImageUrl", typeof(Uri), typeof(CacheableImage), new PropertyMetadata(default(string)));        public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(            "Stretch", typeof (Stretch), typeof (CacheableImage), new PropertyMetadata(default(Stretch), StretchPropertyChangedCallback));        private static void StretchPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)        {            var cachedImage = (CacheableImage)dependencyObject;            var stretch = (Stretch)dependencyPropertyChangedEventArgs.NewValue;            if (cachedImage.Image != null)            {                cachedImage.Image.Stretch = stretch;            }        }        public Stretch Stretch        {            get { return (Stretch) GetValue(StretchProperty); }            set { SetValue(StretchProperty, value); }        }                ///         /// 加载失败的图片        ///         public Uri FaildImageUrl        {            get { return (Uri)GetValue(FaildImageUrlProperty); }            set { SetValue(FaildImageUrlProperty, value); }        }        ///         /// 加载中显示的图片(需要进行网络请求时)        ///         public Uri LoadingImageUrl        {            get { return (Uri)GetValue(LoadingImageUrlProperty); }            set { SetValue(LoadingImageUrlProperty, value); }        }        ///         /// 缓存到本地的目录        ///         public string CachedDirectory        {            get { return (string) GetValue(CachedDirectoryProperty); }            set { SetValue(CachedDirectoryProperty, value); }        }        public static readonly DependencyProperty ImageUrlProperty = DependencyProperty.Register(            "ImageUrl", typeof (string), typeof (CacheableImage), new PropertyMetadata(default(string), ImageUrlPropertyChangedCallback));        public string ImageUrl        {            get { return (string)GetValue(ImageUrlProperty); }            set { SetValue(ImageUrlProperty, value); }        }        private static async void ImageUrlPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)        {            var cachedImage = (CacheableImage) dependencyObject;            var imageUrl = (string)dependencyPropertyChangedEventArgs.NewValue;            if (string.IsNullOrEmpty(imageUrl))            {                return;            }            if (imageUrl.StartsWith("http://") || imageUrl.Equals("https://"))            {                var fileName = cachedImage.CachedDirectory + Uri.EscapeDataString(imageUrl);                //网络图片,判断是否存在                if (!StorageHelper.Instance.FileExist(fileName))                {                    try                    {                        if (cachedImage.LoadingImageUrl != null)                        {                            cachedImage.Image.Source =                                new BitmapImage(cachedImage.LoadingImageUrl);                        }                        //请求                        var request = WebRequest.CreateHttp(imageUrl);                        request.AllowReadStreamBuffering = true;                        var response = await request.GetResponseAsync();                        var stream = response.GetResponseStream();                        await Task.Delay(1000);                        //保存到本地                        StorageHelper.Instance.CreateFile(stream, fileName);                    }                    catch (Exception e)                    {                        //请求失败                        if (cachedImage.FaildImageUrl != null)                        {                            cachedImage.Image.Source = new BitmapImage(cachedImage.FaildImageUrl);                        }                        return;                    }                }                 //读取图片文件                var imageStream = StorageHelper.Instance.ReadFile(fileName);                var bitmapImage = new BitmapImage();                bitmapImage.SetSource(imageStream);                cachedImage.Image.Source = bitmapImage;            }            else            {                //本地图片                var bitmapImage = new BitmapImage(new Uri(imageUrl, UriKind.Relative));                cachedImage.Image.Source = bitmapImage;            }        }                public static readonly DependencyProperty ImageStreamProperty = DependencyProperty.Register(            "ImageStream", typeof (Stream), typeof (CacheableImage), new PropertyMetadata(default(Stream), ImageStreamPropertyChangedCallback));        private static void ImageStreamPropertyChangedCallback(DependencyObject dependencyObject,            DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)        {            var cachedImage = (CacheableImage) dependencyObject;            var imageStream = (Stream) dependencyPropertyChangedEventArgs.NewValue;            var bitmapImage = new BitmapImage();            bitmapImage.SetSource(imageStream);            cachedImage.Image.Source = bitmapImage;        }        ///         /// 支持直接传递流进来        ///         public Stream ImageStream        {            get { return (Stream) GetValue(ImageStreamProperty); }            set { SetValue(ImageStreamProperty, value); }        }    }}

 

为了保证线程安全,这里图片的保存没有用到异步,因为如果有很多图片进行请求的时候,可能会线程请求异常,像上面说的情况

上面的StorageHelper在读取和写入的时候都加了线程锁(其实不应该在读取文件的时候加锁的),是为了保证,在写入的过程中,读取文件出现无权访问的问题

  暂时没有找到方法支持线程安全,如果你有更好的方案,可以给我留言

 

 

 

  

转载地址:http://nbexx.baihongyu.com/

你可能感兴趣的文章
Python中使用ElementTree解析xml
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
CentOS定时同步系统时间
查看>>
批量删除用户--Shell脚本
查看>>
如何辨别android开发包的安全性
查看>>
Eclipse Java @Override 报错
查看>>
知道双字节码, 如何获取汉字 - 回复 "pinezhou" 的问题
查看>>
linux中cacti和nagios整合
查看>>
Parallels Desktop12推出 新增Parallels Toolbox
查看>>
Python高效编程技巧
查看>>
Kafka服务端脚本详解(1)一topics
查看>>
js中var self=this的解释
查看>>
js--字符串reverse
查看>>
面试题
查看>>
Facebook 接入之获取各个配置参数
查看>>
linux的日志服务器关于屏蔽一些关键字的方法
查看>>
事情的两面性
查看>>