Windowphone访问网络图片-本地缓存-封装CacheNetworkFile.dll的学习

这篇博文是我根据一个缓存网络图片的demo的学习总结。

在这个例子中调用的是CacheNetworkFile.dll中的CacheNetworkImageConvert来进行缓存网络图片的。这个CacheNetworkFile.dll里面到底是什么东东呢?

经过神器Reflector的分析原来如此呀

 

类CacheNetworkImageConvert实现了IvalueConverter接口

View Code
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类 原作者连个注释都无有,看起来真蛋疼呀!

View Code
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代码

View Code
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


 

posted @ 2012-08-16 22:20  MicroLeo  阅读(677)  评论(0编辑  收藏  举报