Silverlight技术研讨:图片资源引用及动态下载

转自:http://www.silverlightchina.net/html/tips/2010/1013/2588.html

Silverlight技术研讨:图片资源引用及动态下载

时间:2010-10-13 00:36来源:博客园 作者:叶晓丰 点击: 592次
这一节将总结归纳Silverlight中图片资源引用的几种方法,着重介绍动态下载及缓存。 还是考虑我们的应用:MMORPG游戏,都需要哪些资源呢?主要有两类,音频文件和游戏图片。其实各类资源的引用方法大同小异,这里仅以图片资源为例,讲述一下各种引用方法。 1 图片直接编译到silverlight应用程序的dll当中 这也是缺省的方法,
  

  这一节将总结归纳Silverlight中图片资源引用的几种方法,着重介绍动态下载及缓存。

  还是考虑我们的应用:MMORPG游戏,都需要哪些资源呢?主要有两类,音频文件和游戏图片。其实各类资源的引用方法大同小异,这里仅以图片资源为例,讲述一下各种引用方法。

  1 图片直接编译到silverlight应用程序的dll当中

  这也是缺省的方法,具体做法是:在visual studio中,选择一个图片,查看属性窗口。

  Build Action: Resource (注意不要选择Embeded Resource,Silverlight无法识别该格式。)

  Copy to output directory: Do not copy

  于是在Xaml中可以这样引用图片

       <Image Source="Images/grandpiano.jpg"></Image>

  用C#引用:

  img.Source = new BitmapImage(new Uri("Images/grandpiano.jpg", UriKind.Relative));

  注意BitmapImage对象有个ImageOpened事件,可以用来通知图片已经可用。

  或者:

  img.Source = new BitmapImage(new Uri("/SilverlightApplication1;component/Images/grandpiano.jpg", UriKind.Relative));

  我们还可以选择另外一个相对复杂一些的方法:

1
2
3
4
5
StreamResourceInfo sr = Application.GetResourceStream(
    new Uri("/SilverlightApplication1;component/Images/grandpiano.jpg", UriKind.Relative));
BitmapImage bmp = new BitmapImage();
bmp.SetSource(sr.Stream);  
img.Source = bmp

  注意下面的用法是错误的:

1
2
3
4
5
StreamResourceInfo sr = Application.GetResourceStream(
    new Uri("Images/grandpiano.jpg", UriKind.Relative));
BitmapImage bmp = new BitmapImage();
bmp.SetSource(sr.Stream); 
img.Source = bmp

  运行时会显示错误信息。

  2 把图片资源放到silverlight应用程序的主包(Xap)中

  具体做法是:在visual studio中,选择一个图片,查看属性窗口。

  Build Action: Content

  Copy to output directory: Always copy

  这时候把xap文件改名为zip文件,可以发现Images目录下有grandpiano.jpg文件。说明图片在xap包中,但是没有编译到dll中。

  在Xaml中可以这样引用图片

  Image Source="/Images/grandpiano.jpg">

  注意跟前面的区别:最前面的“/”代表xap文件的根路径。

  用C#引用:

  img.Source = new BitmapImage(new Uri("Images/grandpiano.jpg"));

  或者:

  StreamResourceInfo sr = Application.GetResourceStream(

  new Uri("Images/grandpiano.jpg", UriKind.Relative));

  BitmapImage bmp = new BitmapImage();

  bmp.SetSource(sr.Stream);

  img.Source = bmp;

  注意在C#引用中没有最前面的“/”。

  总的来说,把文件放到主包中与编译到dll中比较相像。但都不是动态下载,因为图片都还在主包中,会跟主程序一同下载。

  3 把图片放到web服务器上

  为方便描述起见,假设图片与silverlight应用程序在同一个域,不存在跨域的问题。为了突出主题,跨域访问的授权许可这里就不讨论了。另外假设图片目录与silverlight主包在同一个目录。即

  /ClientBin/

  App.Xap

  Images/

  具体做法是:在visual studio中,选择一个图片,查看属性窗口。

  build action: None

  Copy to output directory: Always copy

  在Xaml中可以这样引用图片

       <Image Source="/Images/grandpiano.jpg"></Image>

  用C#引用:

  img.Source = new BitmapImage(new Uri("Images/grandpiano.jpg"));

  咦,发现没有?这与方法2完全相同!没错,Silverlight会首先检查xap包,如果没有找到图片,会再检查web服务器。也就是说,相同的代码,你可以在方法2和方法3中自由选择和切换,方便吧?

  方法3虽然与方法2代码相同,本质上已经根本不同。方法3中图片文件已经不在xap文件中,而是在web服务器上,意味着xap文件的尺寸已经大大减小,silverlight应用程序的加载时间大大缩小。缺点是这些图片因为会在引用时动态从服务器下载,直到下载完成才可使用,所以会导致延迟。不过由于Silverlight缓存资源的缘故,只有第一次引用会有延迟,再次引用时将直接从缓存中读取文件,没有丝毫延迟。

  除此之外,更加灵活和强大的方式是使用上节介绍的WebClient类的OpenReadAsync方法。代码如下:

string uri = Application.Current.Host.Source.AbsoluteUri;
int index = uri.IndexOf("/ClientBin"
);
uri
= uri.Substring(0, index) + "/Images/grandpiano.jpg"
;
// Begin the download.

WebClient webClient = new WebClient();
webClient.OpenReadCompleted
+=
webClient_OpenReadCompleted;
webClient.OpenReadAsync(
new
Uri(uri));

//

private void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null
)
{
// (Add code to display error or degrade gracefully.)

}
else

{
    BitmapImage bitmapImage
= new BitmapImage();
    bitmapImage.SetSource(e.Result);
    img.Source
=
bitmapImage;
}
}

  前一节讲过webClient与浏览器共享缓存,即webClient会把下载的文件保存到浏览器缓存目录中,如果文件已经被缓存,再次调用OpenReadAsync方法时将直接中缓存中获得文件,这将大大减小获取文件的时间。但是从浏览器缓存获取文件仍然会有一点点延迟,通常不会被察觉,但是如果用于显示动画,这个延迟会导致严重闪烁。解决这个问题的办法就是把下载的资源保存到silverlight的内存中,引用时直接从内存读取。Application.Resources是个不错的选择,可以用于资源缓存。

  4. 把图片打包放到web服务器上

  把图片打包放置到web服务器上更便于图片资源的管理和维护,而且可以把图片分类保存到不同的压缩包里。因为下载图片时通常是同类图片一起下载,下载一个包当然比分开下载许多图片方便快捷许多。

  具体方法是把图片打包(zip)后,放置到ClientBin目录。然后代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<PRE class=brush:csharp>void DownloadImagePart(string imgPart)  

02 {  

03     WebClient wc = new WebClient();  

04     wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);  

05     wc.OpenReadAsync(new Uri("imgs.zip", UriKind.Relative), imgPart);  

06 }  

07    

08 void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)  

09 {  

10     StreamResourceInfo sri = new StreamResourceInfo(e.Result as Stream, null);  

11     String sURI = e.UserState as String;  

12     StreamResourceInfo imageStream = Application.GetResourceStream(sri, new Uri(sURI, UriKind.Relative));  

13     BitmapSource imgsrc = new BitmapSource ();  

14     imgsrc.SetSource(imageStream.Stream);  

15     ImgToFill.Source = imgsrc;  

16 }  

17    

18 </PRE>  

19 <P> </P>  

20 <P> </P>  

21 <P> </P>

  至此图片引用以及动态下载和缓存的技术讨论完毕了,应该说几乎囊括了主要的引用方式,大家可以根据具体情况选用其中的方法。如果还有其他方法没有收录进来,欢迎大家补充。为了方便大家学习和使用,这里附有源码,每个项目文件代表一种方法。

  后面文章将讨论如何把该技术应用到我们的MMORPG游戏中去,实现图片的动态下载策略。谢谢支持!

  参考资料:

  http://msdn.microsoft.com/en-us/library/cc296240(VS.95).aspx

  http://msdn.microsoft.com/en-us/library/cc189021(VS.95).aspx 

本文来自叶晓丰的博客,原文地址:http://www.cnblogs.com/wzyexf/archive/2010/10/13/1849759.html

posted on 2011-06-13 11:35  老咸菜  阅读(375)  评论(0编辑  收藏  举报