在Silverlight中进行图片下载
本篇 QuickStart 示例演示如何使用 Microsoft .NET Framework for Silverlight来下载一个图片内容,并将其嵌入到XAML Image object中.这个sample包括演示在.NET Framework for Silverlight中通过 HTTP POST来调用一个Web service .
运行 查看 想要在基于Silverlight的应用程序中做到以上的功能,你需要准备以下步骤:
通过BrowserHttpWebRequest 和 HttpWebResponse objects来调用Web service.
通过HTTP GET 方法来得到image 文件内容 , 然后使用Downloader object来将其嵌入XAML Image object 中 .
要求 (available from the Silverlight download site):
Microsoft Silverlight 1.1 Alpha.
Microsoft Visual Studio Code Name "Orcas" Beta 1.
Microsoft Silverlight Tools Alpha for Visual Studio Code Name "Orcas" Beta 1.
An ASP.NET Web site.
一个 Silverlight project. 查看 怎么样创建一个Silverlight Project .
使用Downloader来下载一个 Image
你可能对HTML img tag很熟悉, 它控制显示一个image 到 Web page中.在本篇的场景中,你设置img tag的 src 属性指向到一个浏览器可以下载到图片的 Uniform Resource Identifier (URI) . 同样的, 你也可以设置XAML Image object 的 Source 属性指向一个 image文件的 URI 来达到同样的目的. Silverlight 提供给了你额外的选择: 你可以使用 Downloader object 来下载image 文件内容然后通过SetSource 方法把内容应用到 XAML Image object 中 .
Downloader object 执行一个对特定URI的 HTTP request 然后异步的接收这个响应. 这样,你需要为Downloader object的Completed 事件定义一个event handler,以此来处理下载完成后的事情. 请求的发送通过使用Downloader object的Open 和 Send 方法 .
接下来的示例讲解如何使用Open 和 Send 方法,同样还将建立 Downloader object的Completed 事件的event handler .这个示例中在类开始处定义了 Downloader object 然后在XAML Canvas object的Loaded 事件中关联.
CS
public void GetImage(string imageName){// Request the image file contents. _downloader.Open("GET", new Uri(imageName, UriKind.Relative), true);_downloader.Send();}public void DownloaderCompleted(object o, EventArgs e){// Populate the XAML Image object with the image file contents. ImageFrame.SetSource(_downloader, null);}
VB
Public Sub GetImage(ByVal imageName As String)' Request the image file contents. _downloader.Open("GET", New Uri(imageName, UriKind.Relative), True)_downloader.Send()End SubPublic Sub DownloaderCompleted(ByVal o As Object, ByVal e As EventArgs)' Populate the XAML Image object with the image file contents. ImageFrame.SetSource(_downloader, Nothing)End Sub
调用Web Service
因为 Silverlight 代码是运行在client browser中的, 它不可以直接访问 Web server的资源, 比如像文件系统. 这个示例中提供提供一个简单的方法来浏览服务器上的图片文件夹. 为了让Silverlight 得到哪些文件可以下载的信息, Silverlight 需要知道服务器上的文件夹中的文件的文件名列表.这个示例使用 Web service 来达到这个目的.
你可以在Silverlight code中使用HTTP POST request来调用Web service. 可以使用 BrowserHttpWebRequest object 来在browser中创建一个HTTP request . 在你发送完 HTTP request后, 你可使用 .NET Framework提供的标准,比如 System.Net.HttpResponse 类来得到response 然后使用 System.Xml.XmlReader 类来格式化response的 内容, 就像下面的示例.
CS
public string[] GetImageList(string folderName){List<string> results = new List<string>();// Create an HTTP request with the path to the web service that// returns a list of images from a specified folder. Uri listService = new Uri("Service.asmx/GetImageList", UriKind.Relative);BrowserHttpWebRequest request = new BrowserHttpWebRequest(listService);request.Method = "POST";request.ContentType = "application/x-www-form-urlencoded";// Set the folderName property for the body of the HTTP request. string formBody = "folderName=" + HttpUtility.UrlEncode(folderName);UTF8Encoding encoding = new UTF8Encoding();byte[] formBytes = encoding.GetBytes(formBody);Stream body = request.GetRequestStream();body.Write(formBytes, 0, formBytes.Length);// Send the request and parse the returned XML for the list of// file names (e.g. <string>image.jpg</string>) HttpWebResponse response = (HttpWebResponse)request.GetResponse();Stream s = response.GetResponseStream();XmlReader reader = XmlReader.Create(s);reader.MoveToContent();while (reader.Read()){if (reader.NodeType == XmlNodeType.Element)if (reader.Name == "string")results.Add(reader.ReadInnerXml());}reader.Close();s.Close();body.Close();return results.ToArray();}
VB
Public Function GetImageList(ByVal folderName As String) As String()Dim results As New List(Of String)' Create an HTTP request with the path to the web service that ' returns a list of images from a specified folder. Dim listService As Uri = New Uri("Service.asmx/GetImageList", UriKind.Relative)Dim request As BrowserHttpWebRequest = New BrowserHttpWebRequest(listService)request.Method = "POST"request.ContentType = "application/x-www-form-urlencoded"' Set the folderName property for the body of the HTTP request. Dim formBody As String = "folderName=" & HttpUtility.UrlEncode(folderName)Dim encoding As UTF8Encoding = New UTF8Encoding()Dim formBytes As Byte() = encoding.GetBytes(formBody)Dim body As Stream = request.GetRequestStream()body.Write(formBytes, 0, formBytes.Length)' Send the request and parse the returned XML for the list of ' file names (e.g. <string>image.jpg</string>) Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)Dim s As Stream = response.GetResponseStream()Dim reader As XmlReader = XmlReader.Create(s)reader.MoveToContent()Do While reader.Read()If reader.NodeType = XmlNodeType.Element Then _If reader.Name = "string" Then _results.Add(reader.ReadInnerXml())Loopreader.Close()s.Close()body.Close()Return results.ToArray()End Function
你可能需要在你的Web application中开启允许使用HTTP POST来调用 Web services . 开启些选项,请在system.web configuration下的webServices configuration 下添加HttpPost到protocols 部分中, 就像下面示例一样.
<system.web><webServices><protocols><add name="HttpPost"/></protocols></webServices></system.web>
想了解更多关于在Silverlight中调用 Web service, 查看 How To: Use a Proxy to Call an ASP.NET Web Service from Silverlight.
编译代码
你可按下面的步骤来拷贝一份代码来在本地运行.
创建一个ASP.NET Web Service
本篇QuickStart示例使用一个Web service来发送一组image文件名到服务器. 因为安全因素, 跨域调用是不允许的. 这样的话, .NET Framework for Silverlight 客户端代码和其调用的Web service必须在同一个域中. 所以, 你必须首先创建一个Web site来包含Silverlight 客户端页面和Web service.
此处创建的Web service 以一个包含image 文件的文件夹名称作为输入, 然后返回一组 image 文件名. 这是因为运行在浏览器中的 Silverlight 客户 代码不能直接访问Web server的文件系统.
创建一个 ASP.NET Web service
在Visual Studio中, 在 File 菜单上, 单击 New Web Site.
在Visual Studio Installed Templates 面板中, 点击 ASP.NET Web Service.
在Location 列表中, 选择 File System.填入你的 Web site的路径, 点击OK.
-或者-
你可以选择 HTTP 来在Internet Information Services (IIS)中创建一个新的Web site 来包含这个示例.
Visual Studio 将创建一个带有默认Web service的ASP.NET Web site .
双击 Service.asmx进行编辑. 对于Visual Basic改变 class="Service" 为 class="SampleDownloadServiceVB" 对于 C#则为Class="SampleDownloadServiceCS" .保存并关闭.
在 App_Code 文件夹中, 双击 Service.cs 或者 Service.vb 文件, 当然这都和你选择的编程语言有关. 替换这些内容为你选择的编程语言.
App_Code
using System;using System.Web;using System.Web.Services;using System.Web.Services.Protocols;using System.Web.Caching;using System.IO;using System.Collections.Generic;[WebService(Namespace = "http://tempuri.org/")]public class SampleDownloadServiceCS : System.Web.Services.WebService{public SampleDownloadServiceCS(){}[WebMethod]public string[] GetImageList(string folderName){List<string> resultsList = new List<string>();FileInfo[] fileList = new DirectoryInfo(Server.MapPath(folderName)).GetFiles();foreach (FileInfo f in fileList){switch (f.Extension){case ".jpg":resultsList.Add(f.Name);break;case ".png":resultsList.Add(f.Name);break;case ".bmp":resultsList.Add(f.Name);break;case ".gif":resultsList.Add(f.Name);break;}}return resultsList.ToArray();}}
App_Code
Imports SystemImports System.WebImports System.Web.ServicesImports System.Web.Services.ProtocolsImports System.Web.CachingImports System.IOImports System.Collections.Generic<WebService(Namespace:="http://tempuri.org/")> _Public Class SampleDownloadServiceVBInherits System.Web.Services.WebServicePublic Sub New()End Sub<WebMethod()> _Public Function GetImageList(ByVal folderName As String) As String()Dim resultsList As New List(Of String)Dim fileList As FileInfo() = New DirectoryInfo(Server.MapPath(folderName)).GetFiles()For Each f As FileInfo In fileListSelect Case f.ExtensionCase ".jpg"resultsList.Add(f.Name)Case ".png"resultsList.Add(f.Name)Case ".bmp"resultsList.Add(f.Name)Case ".gif"resultsList.Add(f.Name)End SelectNextReturn resultsList.ToArray()End FunctionEnd Class
保存并关闭文件.
创建Silverlight Project
Silverlight 客户端代码是被编译的,将被浏览器下载到本地. 这样, 你可以创建几个独立的 project ,并 build 它们到一个assembly, 然后拷贝这些assembly到你的Web site.你同样需要拷贝 XAML 文件来引用这些 assembly, 当然还有一些客户端文件(在这儿, 像HTML 文件) 比如,用来载入XAML Canvas object 的文件.
来创建一个Silverlight project
暂时不管 ASP.NET Web site project . 在Visual Studio中, 在 File 菜单, 点击 Add, 点击 New Project.
在 Visual Studio Installed Templates 面板中, 点击 Silverlight Project.
在 Name 对话框中, 为 project敲入一个名字. 对于Visual Basic输入 ImageViewerVB 对于C#则为ImageViewerCS , 点击 OK.
在Visual Studio Solution Explorer中将显示才创建的 Web site ,还有你新建的 Silverlight project. Silverlight project 将包含一个TestPage.html的 HTML 文件 ,Page.xaml的XAML 文件 , 还有一个partial class与Page.xaml中的XAML Canvas object 引用关系的 C# 或 Visual Basic 文件 .
右击 TestPage.html 文件, 点击 Rename. 改变文件名为 Default.html.
右击 Default.html 来进行编辑. 改变title tag 为 Image Download Sample. 保存并关闭.
右击 Page.xaml 文件进行编辑. 将其内容替换完下面的内容,当然请选择你使用的编程语言. 注意到对于 XAML文件的两种不同编辑语言之间的区别就在于class名称和 XAML Canvas父对象中x:Class 属性中编译好的assembly标识符 .
保存并关闭文件.
右击 Page.xaml.cs 或者 Page.xaml.vb 文件进行编辑. 将它们内容替换成以下内容,当然请先根据你的编辑语言进行选择.
CS
using System;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Ink;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;using System.Net;using System.Text;using System.IO;using System.Xml;using System.Windows.Browser;using System.Windows.Browser.Net;using System.Collections.Generic;namespace ImageViewerCS{public partial class Page : Canvas{// Variables to manage the list of images. private int _imageIndex;private string _imageFolderName = "images";private string[] _imageList;// Downloader object to retrieve the image file contents. private Downloader _downloader = new Downloader();public void Page_Loaded(object o, EventArgs e){InitializeComponent();// Add event handlers for Downloader and XAML elements. _downloader.Completed += DownloaderCompleted;LeftArrow.MouseLeftButtonDown += OnPrevButtonClick;RightArrow.MouseLeftButtonDown += OnNextButtonClick;// Initialize list of image file names. _imageIndex = 0;_imageList = GetImageList("images");// Populate the XAML Image object with a default image. string defaultImageName = GetImageName(_imageIndex);GetImage(defaultImageName);ImageFileName.Text = defaultImageName;}public string[] GetImageList(string folderName){List<string> results = new List<string>();// Create an HTTP request with the path to the web service that// returns a list of images from a specified folder. Uri listService = new Uri("Service.asmx/GetImageList", UriKind.Relative);BrowserHttpWebRequest request = new BrowserHttpWebRequest(listService);request.Method = "POST";request.ContentType = "application/x-www-form-urlencoded";// Set the folderName property for the body of the HTTP request. string formBody = "folderName=" + HttpUtility.UrlEncode(folderName);UTF8Encoding encoding = new UTF8Encoding();byte[] formBytes = encoding.GetBytes(formBody);Stream body = request.GetRequestStream();body.Write(formBytes, 0, formBytes.Length);// Send the request and parse the returned XML for the list of// file names (e.g. <string>image.jpg</string>) HttpWebResponse response = (HttpWebResponse)request.GetResponse();Stream s = response.GetResponseStream();XmlReader reader = XmlReader.Create(s);reader.MoveToContent();while (reader.Read()){if (reader.NodeType == XmlNodeType.Element)if (reader.Name == "string")results.Add(reader.ReadInnerXml());}reader.Close();s.Close();body.Close();return results.ToArray();}public void GetImage(string imageName){// Request the image file contents. _downloader.Open("GET", new Uri(imageName, UriKind.Relative), true);_downloader.Send();}public void DownloaderCompleted(object o, EventArgs e){// Populate the XAML Image object with the image file contents. ImageFrame.SetSource(_downloader, null);}public void OnPrevButtonClick(object o, EventArgs e){// Request the previous image from the list. string imageName = GetImageName(_imageIndex - 1);GetImage(imageName);ImageFileName.Text = imageName;}public void OnNextButtonClick(object o, EventArgs e){// Request the next image from the list. string imageName = GetImageName(_imageIndex + 1);GetImage(imageName);ImageFileName.Text = imageName;}private string GetImageName(int index){// Retrieve the requested image file name from the list and// update the index value. if (the requested index exceeds the// length of the list, set the index to the beginning of the// list (0). if (the requested index is less than 0, set the index// to the last element in the list. _imageIndex = index;if (index >= _imageList.Length)_imageIndex = 0;if (index < 0)_imageIndex = _imageList.Length - 1;return _imageFolderName + "/" + _imageList[_imageIndex];}}}
VB
Imports SystemImports System.WindowsImports System.Windows.ControlsImports System.Windows.DocumentsImports System.Windows.InkImports System.Windows.InputImports System.Windows.MediaImports System.Windows.Media.AnimationImports System.Windows.ShapesImports System.NetImports System.TextImports System.IOImports System.XmlImports System.Windows.BrowserImports System.Windows.Browser.NetImports System.Collections.GenericPartial Public Class PageInherits Canvas' Variables to manage the list of images. Private _imageIndex As IntegerPrivate _imageFolderName As String = "images"Private _imageList As String()' Downloader object to retrieve the image file contents. Private _downloader As New Downloader()Public Sub Page_Loaded(ByVal o As Object, ByVal e As EventArgs)InitializeComponent()'' Add event handlers for Downloader and XAML elements.AddHandler _downloader.Completed, AddressOf DownloaderCompletedAddHandler LeftArrow.MouseLeftButtonDown, AddressOf OnPrevButtonClickAddHandler RightArrow.MouseLeftButtonDown, AddressOf OnNextButtonClick'' Initialize list of image file names._imageIndex = 0_imageList = GetImageList("images")' Populate the XAML Image object with a default image. Dim defaultImageName As String = GetImageName(_imageIndex)GetImage(defaultImageName)ImageFileName.Text = defaultImageNameEnd SubPublic Function GetImageList(ByVal folderName As String) As String()Dim results As New List(Of String)' Create an HTTP request with the path to the web service that ' returns a list of images from a specified folder. Dim listService As Uri = New Uri("Service.asmx/GetImageList", UriKind.Relative)Dim request As BrowserHttpWebRequest = New BrowserHttpWebRequest(listService)request.Method = "POST"request.ContentType = "application/x-www-form-urlencoded"' Set the folderName property for the body of the HTTP request. Dim formBody As String = "folderName=" & HttpUtility.UrlEncode(folderName)Dim encoding As UTF8Encoding = New UTF8Encoding()Dim formBytes As Byte() = encoding.GetBytes(formBody)Dim body As Stream = request.GetRequestStream()body.Write(formBytes, 0, formBytes.Length)' Send the request and parse the returned XML for the list of ' file names (e.g. <string>image.jpg</string>) Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)Dim s As Stream = response.GetResponseStream()Dim reader As XmlReader = XmlReader.Create(s)reader.MoveToContent()Do While reader.Read()If reader.NodeType = XmlNodeType.Element Then _If reader.Name = "string" Then _results.Add(reader.ReadInnerXml())Loopreader.Close()s.Close()body.Close()Return results.ToArray()End FunctionPublic Sub GetImage(ByVal imageName As String)' Request the image file contents. _downloader.Open("GET", New Uri(imageName, UriKind.Relative), True)_downloader.Send()End SubPublic Sub DownloaderCompleted(ByVal o As Object, ByVal e As EventArgs)' Populate the XAML Image object with the image file contents. ImageFrame.SetSource(_downloader, Nothing)End SubPublic Sub OnPrevButtonClick(ByVal o As Object, ByVal e As EventArgs)' Request the previous image from the list. Dim imageName As String = GetImageName(_imageIndex - 1)GetImage(imageName)ImageFileName.Text = imageNameEnd SubPublic Sub OnNextButtonClick(ByVal o As Object, ByVal e As EventArgs)' Request the next image from the list. Dim imageName As String = GetImageName(_imageIndex + 1)GetImage(imageName)ImageFileName.Text = imageNameEnd SubPrivate Function GetImageName(ByVal index As Integer) As String' Retrieve the requested image file name from the list and ' update the index value. If the requested index exceeds the ' length of the list, set the index to the beginning of the ' list (0). If the requested index is less than 0, set the index ' to the last element in the list. _imageIndex = indexIf index >= _imageList.Length Then _imageIndex = 0If index < 0 Then _imageIndex = _imageList.Length - 1Return _imageFolderName & "/" & _imageList(_imageIndex)End FunctionEnd Class
保存并关闭文件.
右击Silverlight project的project 文件, 点击 Build. 默认情况下, Silverlight project将会配置为将编译好的assembly保存到 ClientBin文件夹中. 选择 Silverlight project. 在 Project 菜单, 点击 Show All Files 使 ClientBin 文件夹变为可见.
拷贝Silverlight Assembly 和文件到Web Site
到目前, 你只要拷贝你的 Silverlight project到 Web site就可以运行了. 你需要拷贝client HTML 文件, XAML 文件, 还有编译好的 assembly 到你的Web site 来运行.
拷贝 Silverlight assembly 和 文件 到Web site
在 Solution Explorer, 在Silverlight project, 右击 Page.xaml 文件,点击 Copy.
在 Solution Explorer,点击 Web site project, 点击 Paste. ( Page.xaml.cs 或者 Page.xaml.vb 也将被拷贝. 你可以删除这些.)
在Solution Explorer, 在 Silverlight project, 右击 Default.xml 文件, 点击 Copy.
在 Solution Explorer, 右击 Web site project, 点击 Paste ( TestPage.html.js 文件也将被拷贝过来).
右击 Web site project, 点击 New Folder.命名为 ClientBin.
在Solution Explorer, 点击 Silverlight project的project文件. 点击 Project 菜单, 点击 Show All Files.你将看到 ClientBin 文件夹. 展开这个文件夹, 右击 ImageViewerVB.dll 或者 ImageViewerCS.dll 文件, 点击 Copy.
在 Solution Explorer,右击 ClientBin文件夹, 点击Paste.
右击 Web site project, 点击 New Folder.命名为 images.
右击images 文件夹, 点击 Add Existing Item, 浏览 JPEG 或者 PNG 文件. 拷贝一些 JPEG或者 PNG 文件到images文件夹中.
在 Web site project, 右击 default.html 文件, 点击 View in Browser来运行这个示例.