windows phone7 下 Silverlight 异步读取网络图片
来源:互联网 发布:t局域网通讯软件 编辑:程序博客网 时间:2024/06/05 00:55
项目有这样的需求,XAML页面代码如下:
要求窗口加载一揽子图片,为了不让UI阻塞太久,采用异步读取后绑定显示的方案.
图片的下载应该采用并发的过程(等待网络响应会很耗时,一张一张的下载,等待时间太长)
图片的下载不能占用过多的线程数,应有个阀值(图片不是核心业务,不能占用那么多资源)
在图片加载的过程中,如果用户有操作,比如窗口跳转,则未加载完成的图片加载的过程应取消(为了替用户节省流量).
需求就是这么多了,如何实现呢?
思路是这样的,由于需要异步,且需要等待,首先想到使用队列,先让队列排列起来,再定量迭代读取.
因为要涉及异步的取消,想到了用WebClient对象的异步功能, 当然,所以发起异步请求之后的对象我都需要记录,
所以还需要一个list容器.
外部接口是两个参数,url,图片的网址,一个回调,定义了图片下载完成后的操作.
内部的核心流程,
1.将一个图片任务从队列中取出,
2.异步发生此请求,
3.将发起请求的对象放进容器,以备撤销时使用.
撤销的核心流程是.
1.让处理线程停止
2.取消队列中的任务,
3.让等待响应的任务取消.
需要用到以下命名空间:
using System;using System.Collections.Generic;using System.Net;using System.Windows;using Microsoft.Phone.Controls;using System.Windows.Media.Imaging;using System.IO;using System.ComponentModel;using System.Threading;
先声明两个回调
public delegate void GetDataStreamCallback(Stream stream); public delegate void GetPicCallback(BitmapSource bimage);
第一个是从网络读取流的回调,第二个是生成了图片源之后的回调.
定义了一个接口:
/// <summary>/// 可以撤销的操作 /// </summary>interface IRevocable { void RevokeAsync(); event Action ProcessCompleted; }
一个方法,是用来撤销操作的,
一个事件,是当异步完成时触发的.(不管是正常完成还是撤销,都视为操作完成)
做一个类继承该接口,用来获取网络数据
public class HttpResourceGet : IRevocable { public event GetDataStreamCallback OnDataStreamGenerated; public event Action ProcessCompleted; WebClient m_client; public HttpResourceGet() { m_client = new WebClient(); m_client.OpenReadCompleted += ((send, ev) => { do { if (ev.Error != null || ev.Cancelled) { break; } if (OnDataStreamGenerated != null) { OnDataStreamGenerated(ev.Result); ev.Result.Close(); } } while (false); if (ProcessCompleted != null) { ProcessCompleted(); } }); } public void BeginGetData(string url) { m_client.OpenReadAsync(new Uri(url)); } public void RevokeAsync() { m_client.CancelAsync(); } }
再做一个类,把网络数据包装为图片源
public class HttpPicGet : IRevocable { public event GetPicCallback OnImageLoadCompleted; public event Action ProcessCompleted; HttpResourceGet m_httpGet; public HttpPicGet() { m_httpGet = new HttpResourceGet(); m_httpGet.OnDataStreamGenerated += (stream => { BitmapSource bi = new BitmapImage(); bi.SetSource(stream); if (OnImageLoadCompleted != null) { OnImageLoadCompleted(bi); } }); m_httpGet.ProcessCompleted += (() => { if (ProcessCompleted != null) { ProcessCompleted(); } }); } public void BeginLoadPic(string url) { m_httpGet.BeginGetData(url); } public void RevokeAsync() { m_httpGet.RevokeAsync(); } }
做一个容器,用来处理多条任务
public class RevocableContainer { private class QueueItem { public GetPicCallback action; public string url; } const int Threshold = 3; AutoResetEvent m_event; int m_count; bool m_isThreadProcessing; Queue<QueueItem> m_queue; List<IRevocable> m_list; object m_lock; public RevocableContainer() { m_event = new AutoResetEvent(false); m_queue = new Queue<QueueItem>(); m_list = new List<IRevocable>(); m_lock = new object(); m_count = Threshold; m_isThreadProcessing = false; } void HttpRequestThread() { while (true) { if (m_count == 0) { m_event.WaitOne(); } QueueItem item = null; //out from queuelock (m_queue) { if (!m_isThreadProcessing) { break; } if (m_queue.Count == 0) { break; } item = m_queue.Dequeue(); Interlocked.Decrement(ref m_count); } //do request HttpPicGet pic = new HttpPicGet(); pic.OnImageLoadCompleted += (img => { item.action(img); }); pic.ProcessCompleted += (() => { lock (m_list) { m_list.Remove(pic); } if (m_count == 0) { m_event.Set(); } Interlocked.Increment(ref m_count); }); pic.BeginLoadPic(item.url); //into listlock (m_list) { m_list.Add(pic); } Thread.Sleep(1); } } public void EnQueue(string url, GetPicCallback action) { QueueItem item = new QueueItem() { action = action, url = url }; BackgroundWorker worker = null; lock (m_queue) { m_queue.Enqueue(item); if (!m_isThreadProcessing) { m_isThreadProcessing = true; worker = new BackgroundWorker(); } } if (worker != null) { worker.DoWork += ((send, ev) => HttpRequestThread()); worker.RunWorkerCompleted += ((send, ev) => { lock (m_queue) { m_isThreadProcessing = false; } }); worker.RunWorkerAsync(); } } public void CancelAll() { lock (m_queue) { m_isThreadProcessing = false; m_queue.Clear(); } lock (m_list) { foreach (IRevocable item in m_list) { item.RevokeAsync(); } } } }
做异步绑定需要的类
public class MyImage : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; string m_url; BitmapSource m_source; public string URL { get { return m_url; } set { if (m_url != value) { m_url = value; OnPropertyChanged(new PropertyChangedEventArgs("URL")); } } } public BitmapSource Source { get { return m_source; } set { if (m_source != value) { m_source = value; OnPropertyChanged(new PropertyChangedEventArgs("Source")); } } } protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) { if (PropertyChanged != null) PropertyChanged(this, args); } }
业务的部分都做完了
接下来就是做一个例子来验证成果了
public partial class MainPage : PhoneApplicationPage { RevocableContainer m_container = new RevocableContainer(); // Constructorpublic MainPage() { InitializeComponent(); } private void DoClick(object sender, RoutedEventArgs e) { string[] sources = new string[] { "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526395.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526396.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526397.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526398.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526399.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526400.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526401.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526402.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526403.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526404.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526405.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526406.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526407.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526408.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526409.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526410.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526411.jpg", "http://gb.cri.cn/mmsource/images/2008/05/26/ei080526412.jpg" }; MyImage[] imgs = new MyImage[sources.Length]; for (int i = 0; i < imgs.Length; ++i) { imgs[i] = new MyImage(); MyImage imgItem = imgs[i]; imgItem.URL = sources[i]+ "?rand=" + Guid.NewGuid().ToString();//加Guid保证调试时无缓存m_container.EnQueue(imgItem.URL, (bitsource => imgItem.Source = bitsource)); } lbContent.DataContext = imgs; } private void RevokeClick(object sender, RoutedEventArgs e) { m_container.CancelAll(); } }
<!--LayoutRoot is the root grid where all page content is placed--><Grid x:Name="LayoutRoot" Background="Transparent"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><ListBox Height="670" x:Name="lbContent" Grid.Row="0" ItemsSource="{Binding}"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><Image Height="100" Width="100" Source="{Binding Source, Mode=OneWay}" /><TextBlock Text="{Binding URL}" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox><!--ContentPanel - place additional content here--><Grid x:Name="ContentPanel" Grid.Row="1" VerticalAlignment="Bottom" Margin="12,0,12,0"><StackPanel Orientation="Horizontal"><Button x:Name="btnDo" Width="100" Height="100" Content="DO" Click="DoClick" /><Button x:Name="btnRevoke" Width="100" Height="100" Content="Revoke" Click="RevokeClick"/></StackPanel></Grid></Grid>
运行起来,达到需要所要求的效果
- windows phone7 下 Silverlight 异步读取网络图片
- windows phone7 下 Silverlight 异步读取网络图片
- windows phone7 下 Silverlight 异步读取网络图片
- windows phone7 下 Silverlight 异步读取网络图片
- silverlight-windows-phone7
- windows phone7的数据读取
- Silverlight 和 Windows Phone7 中的MD5加密
- Windows Phone7 Image控件显示网络图片的两种方式
- Android 利用 AsyncTask 异步读取网络图片
- windows phone7 免费 网络中文输入平台
- Windows Phone7+Web Service的图片图片上传解决方案
- Silverlight下载网络图片
- Silverlight下载网络图片
- java异步读取网络
- Windows Phone7中的IronRuby
- Windows Phone7的新版本
- windows phone7.5
- windows phone7 模拟器试用
- SilverLight-摄像头捕获图像案例
- Silverlight中DataGrid控件动态生成列并结合DataPager进行分页
- WINDOW7蓝屏错误代码、使用常见问题、解决方法汇总
- Silverlight中的导航总结
- 一个简单的小程序演示Unity的三种依赖注入方式
- windows phone7 下 Silverlight 异步读取网络图片
- 布尔代数和搜索引擎的索引
- FB4.5 模型驱动开发环境配置
- wordpress中常用的插件整理
- Letter to a Young Developer
- 关于arm时钟频率的设置及编程
- 如何做一名优秀的博士生
- ORACLE 2011 OCP 考试试题精讲
- 关于Dbank网盘