windows phone7 下 Silverlight 异步读取网络图片

项目有这样的需求,

要求窗口加载一揽子图片,为了不让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 queue
lock (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 list
lock (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();
// Constructor
public 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();
}
}

XAML页面代码如下:

<!-- 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 >

运行起来,达到需要所要求的效果

转载于:https://www.cnblogs.com/gibbon/archive/2011/04/08/2009704.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值