这篇博文是我根据一个缓存网络图片的demo的学习总结。
在这个例子中调用的是CacheNetworkFile.dll中的CacheNetworkImageConvert来进行缓存网络图片的。这个CacheNetworkFile.dll里面到底是什么东东呢?
经过神器Reflector的分析原来如此呀
类CacheNetworkImageConvert实现了IvalueConverter接口
public class CacheNetworkImageConvert : IValueConverter { // Methods public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Uri uri; BitmapImage2 image; if (value != null) { uri = null; if (value is string) { uri = new Uri((string) value); goto Label_0030; } if (value is Uri) { uri = (Uri) value; goto Label_0030; } } return null; Label_0030: image = new BitmapImage2(); CacheNetworkdFile.AddBind(uri, image, BitmapImage2.Source);//调用CacheNetWorkFile的Addbind方法来保存File return image; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } // Nested Types private class BitmapImage2 : BitmapSource { // Fields public static DependencyProperty Source = DependencyProperty.Register("Source", typeof(Stream), typeof(CacheNetworkImageConvert.BitmapImage2), new PropertyMetadata(null, new PropertyChangedCallback(null, (IntPtr) SourceChanged))); // Methods private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((CacheNetworkImageConvert.BitmapImage2) d).SetSource((Stream) e.get_NewValue()); ((Stream) e.get_NewValue()).Dispose(); } } }
这个是长长多大CacheNetworkdFile类 原作者连个注释都无有,看起来真蛋疼呀!
public class CacheNetworkdFile { // Fields private static List<propertybind> _bindlist = new List<propertybind>(10); private static Dictionary<Uri, CacheNetworkdFile> _cachelist = new Dictionary<Uri, CacheNetworkdFile>(10); private static DispatcherTimer _dispatchertimer; private Uri _uri; private const string directory = "CacheNetworkdFile"; private EventHandler downloaderror; private static volatile Stack<Uri> downloadlist = new Stack<Uri>(10); private static volatile IsolatedStorageFile iso; private EventHandler streamready; private static volatile WebClient wc = new WebClient(); // Events internal event EventHandler downloaderror { add { EventHandler handler2; EventHandler downloaderror = this.downloaderror; do { handler2 = downloaderror; EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value); downloaderror = Interlocked.CompareExchange<EventHandler>(ref this.downloaderror, handler3, handler2); } while (downloaderror != handler2); } remove { EventHandler handler2; EventHandler downloaderror = this.downloaderror; do { handler2 = downloaderror; EventHandler handler3 = (EventHandler) Delegate.Remove(handler2, value); downloaderror = Interlocked.CompareExchange<EventHandler>(ref this.downloaderror, handler3, handler2); } while (downloaderror != handler2); } } internal event EventHandler streamready { add { EventHandler handler2; EventHandler streamready = this.streamready; do { handler2 = streamready; EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value); streamready = Interlocked.CompareExchange<EventHandler>(ref this.streamready, handler3, handler2); } while (streamready != handler2); } remove { EventHandler handler2; EventHandler streamready = this.streamready; do { handler2 = streamready; EventHandler handler3 = (EventHandler) Delegate.Remove(handler2, value); streamready = Interlocked.CompareExchange<EventHandler>(ref this.streamready, handler3, handler2); } while (streamready != handler2); } } // Methods static CacheNetworkdFile() { DispatcherTimer timer = new DispatcherTimer(); timer.set_Interval(new TimeSpan(0, 0, 1)); _dispatchertimer = timer; iso = null; iso = IsolatedStorageFile.GetUserStoreForApplication(); CacheExpire = new TimeSpan(3, 0, 0, 0); wc.add_OpenReadCompleted(new OpenReadCompletedEventHandler(null, (IntPtr) wc_OpenReadCompleted)); _dispatchertimer.add_Tick(new EventHandler(CacheNetworkdFile._dispatchertimer_Tick)); _dispatchertimer.Start(); } private CacheNetworkdFile(Uri uri) { this._uri = uri; } private static void _dispatchertimer_Tick(object sender, EventArgs e) { NextDownload(); } public static void AddBind(Uri uri, DependencyObject obj, DependencyProperty property) { propertybind propertybind2 = new propertybind { _uri = uri, _obj = obj, _property = property }; propertybind item = propertybind2; if (!_bindlist.Contains(item)) { _bindlist.Add(item); } downloadlist.Push(uri); CacheNetworkdFile cacheNetworkFile = GetCacheNetworkFile(uri); if (cacheNetworkFile.ExistCache) { cacheNetworkFile.OnStreamReady(); } } private static void c_streamready(object sender, EventArgs e) { <>c__DisplayClass4 class2; CacheNetworkdFile file = (CacheNetworkdFile) sender; Uri u = file._uri; propertybind[] propertybindArray = Enumerable.ToArray<propertybind>(Enumerable.Where<propertybind>(_bindlist, new Func<propertybind, bool>(class2, (IntPtr) this.<c_streamready>b__3))); if ((propertybindArray != null) && (propertybindArray.Length != 0)) { for (int i = 0; i < propertybindArray.Length; i++) { DateTime time; Stream stream = file.LoadStream(out time); propertybindArray[i].bind(stream, time); } } } private static CacheNetworkdFile GetCacheNetworkFile(Uri uri) { if (uri == null) { throw new NullReferenceException("Uri can not be empty."); } if (!_cachelist.ContainsKey(uri)) { CacheNetworkdFile file = new CacheNetworkdFile(uri); _cachelist.Add(uri, file); file.streamready += new EventHandler(CacheNetworkdFile.c_streamready); downloadlist.Push(uri); NextDownload(); } return _cachelist[uri]; } private DateTime GetLastWriteTime() { string str = SHA256(this._uri.ToString().ToLower()); lock (iso) { if (iso.FileExists(@"CacheNetworkdFile\" + str)) { return iso.GetLastWriteTime(@"CacheNetworkdFile\" + str).DateTime; } return DateTime.MinValue; } } private Stream LoadStream(out DateTime filemodifydate) { string str = SHA256(this._uri.ToString().ToLower()); lock (iso) { if (iso.FileExists(@"CacheNetworkdFile\" + str)) { IsolatedStorageFileStream stream = iso.OpenFile(@"CacheNetworkdFile\" + str, FileMode.Open); MemoryStream stream2 = new MemoryStream(); byte[] buffer = new byte[0x4000]; while (true) { int count = stream.Read(buffer, 0, buffer.Length); if (count == 0) { break; } stream2.Write(buffer, 0, count); } stream.Close(); stream.Dispose(); filemodifydate = iso.GetLastWriteTime(@"CacheNetworkdFile\" + str).DateTime; return stream2; } } filemodifydate = DateTime.MinValue; return null; } private static void NextDownload() { if (!wc.get_IsBusy() && (downloadlist.Count > 0)) { Uri uri = downloadlist.Pop(); CacheNetworkdFile cacheNetworkFile = GetCacheNetworkFile(uri); if ((DateTime.Now - cacheNetworkFile.GetLastWriteTime()) > CacheExpire) { wc.OpenReadAsync(uri, uri); } else { NextDownload(); } } } private void OnDownloadError() { if (this.downloaderror != null) { this.downloaderror(this, new EventArgs()); } } private void OnStreamReady() { if (this.streamready != null) { this.streamready(this, new EventArgs()); } } public static void RemoveBind(Uri uri, DependencyObject obj, DependencyProperty property) { propertybind propertybind2 = new propertybind { _uri = uri, _obj = obj, _property = property }; propertybind item = propertybind2; if (_bindlist.Contains(item)) { _bindlist.Remove(item); } } private void SaveStream(Stream sm) { string str = SHA256(this._uri.ToString().ToLower()); lock (iso) { if (!iso.DirectoryExists("CacheNetworkdFile")) { iso.CreateDirectory("CacheNetworkdFile"); } IsolatedStorageFileStream stream = iso.OpenFile(@"CacheNetworkdFile\" + str, FileMode.Create, FileAccess.Write); byte[] buffer = new byte[0x4000]; while (true) { int count = sm.Read(buffer, 0, buffer.Length); if (count == 0) { break; } stream.Write(buffer, 0, count); stream.Flush(); } stream.Close(); stream.Dispose(); } } private static string SHA256(string src) { if (string.IsNullOrEmpty(src)) { return ""; } return SHA256(Encoding.UTF8.GetBytes(src)); } private static string SHA256(byte[] src) { if ((src == null) || (src.Length == 0)) { return ""; } byte[] buffer = new SHA256Managed().ComputeHash(src); StringBuilder builder = new StringBuilder(); for (int i = 0; i < buffer.Length; i++) { builder.Append(buffer[i].ToString("X2")); } return builder.ToString(); } private static void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { if ((e.UserState != null) && (e.UserState is Uri)) { CacheNetworkdFile cacheNetworkFile = GetCacheNetworkFile((Uri) e.UserState); if ((e.Cancelled || (e.Error != null)) || (e.get_Result() == null)) { cacheNetworkFile.OnDownloadError(); } else { cacheNetworkFile.SaveStream(e.get_Result()); e.get_Result().Close(); e.get_Result().Dispose(); cacheNetworkFile.OnStreamReady(); } } NextDownload(); } // Properties public static TimeSpan CacheExpire { [CompilerGenerated] get { return <CacheExpire>k__BackingField; } [CompilerGenerated] set { <CacheExpire>k__BackingField = value; } } private bool ExistCache { get { string str = SHA256(this._uri.ToString().ToLower()); lock (iso) { if (iso.FileExists(@"CacheNetworkdFile\" + str)) { if (NetworkInterface.GetIsNetworkAvailable()) { DateTime dateTime = iso.GetLastWriteTime(@"CacheNetworkdFile\" + str).DateTime; return ((DateTime.Now - dateTime) <= CacheExpire); } return true; } return false; } } } // Nested Types private class propertybind { // Fields public DependencyObject _obj; public DependencyProperty _property; public Uri _uri; private DateTime updatefilever = DateTime.MinValue; // Methods public void bind(object value, DateTime filemodifydate) { if ((((filemodifydate > DateTime.MinValue) && (this._uri != null)) && (this._property != null)) && (this._obj != null)) { this._obj.get_Dispatcher().BeginInvoke(new setvalue(this._obj.SetValue), new object[] { this._property, value }); } } public override bool Equals(object obj) { if (obj == null) { return false; } if (!(obj is CacheNetworkdFile.propertybind)) { return false; } CacheNetworkdFile.propertybind propertybind = (CacheNetworkdFile.propertybind) obj; if (this._uri != propertybind._uri) { return false; } if (this._obj != propertybind._obj) { return false; } if (this._property != propertybind._property) { return false; } return true; } public override int GetHashCode() { int hashCode = 0; if (this._uri != null) { hashCode = this._uri.GetHashCode(); } if (this._obj != null) { hashCode = (hashCode == 0) ? this._obj.GetHashCode() : (hashCode ^ this._obj.GetHashCode()); } if (this._property != null) { hashCode = (hashCode == 0) ? this._property.GetHashCode() : (hashCode ^ this._property.GetHashCode()); } return hashCode; } public static bool operator ==(CacheNetworkdFile.propertybind a, CacheNetworkdFile.propertybind b) { return a.Equals(b); } public static bool operator !=(CacheNetworkdFile.propertybind a, CacheNetworkdFile.propertybind b) { return !a.Equals(b); } // Nested Types private delegate void setvalue(DependencyProperty p, object v); } } Collapse Methods
在项目添加对这个Dll的应用
在MainPage.xaml中添加
xmlns:bw="clr-namespace:b_wind.WindowsPhone.Cache;assembly=CacheNetworkFile"
在添加资源
<phone:PhoneApplicationPage.Resources> <bw:CacheNetworkImageConvert x:Key="CacheImageConvert1" /> </phone:PhoneApplicationPage.Resources>
MainPage.xaml的设计界面
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ListBox Height="481" HorizontalAlignment="Left" Margin="-4,120,0,0" Name="listBox1" VerticalAlignment="Top" Width="460"> <ListBox.ItemTemplate> <DataTemplate> <Image Height="106" Width="153" Source="{Binding Converter={StaticResource CacheImageConvert1}}"></Image> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Button Content="加载图片" Height="72" Name="button1" Width="160" Margin="308,-13,-12,548" Click="button1_Click" /> <Button Content="清空列表" Height="72" HorizontalAlignment="Left" Margin="151,52,0,0" Name="button2" VerticalAlignment="Top" Width="160" Click="button2_Click" /> <Button Content="清空缓存" Height="72" HorizontalAlignment="Left" Margin="151,-13,0,0" Name="button3" VerticalAlignment="Top" Width="160" Click="button3_Click" /> <Button Content="添加项" Height="72" HorizontalAlignment="Left" Margin="308,52,0,0" Name="button4" VerticalAlignment="Top" Width="160" Click="button4_Click" /> </Grid>
MainPage.xaml.cs代码
public partial class MainPage : PhoneApplicationPage { ObservableCollection<string> l = new ObservableCollection<string>(); // Constructor public MainPage() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { l.Clear(); l.Add("http://bbs.51credit.com/static/image/common/pn_post.png"); l.Add("http://ww4.sinaimg.cn/thumbnail/7cf05c2djw1drbb4m2rw2j.jpg"); l.Add("http://ww1.sinaimg.cn/thumbnail/6c27f3a4jw1drbc2v6bmsj.jpg"); l.Add("http://ww4.sinaimg.cn/thumbnail/6b6e567cjw1drb3plcg4sj.jpg"); l.Add("http://ww3.sinaimg.cn/thumbnail/64d25c69jw1dr7smoyg41j.jpg"); listBox1.ItemsSource = l; } private void button2_Click(object sender, RoutedEventArgs e) { l.Clear(); } private void button3_Click(object sender, RoutedEventArgs e) { using (var iso = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) { iso.Remove(); } } private void button4_Click(object sender, RoutedEventArgs e) { l.Add("http://ww3.sinaimg.cn/thumbnail/62037b5ajw1drd8g24zn9j.jpg"); } }
源代码下载地址:http://vdisk.weibo.com/s/aFuJX