Silverlight之文件上传组件

Silverlight之文件上传组件,第1张

概述摘要: 文件上传是日常开过程中最常用的功能之一,目前实现文件上传的方式多种多样。这其中较为复杂的情况就是关于大文件、多文件上传的问题,目前解决大文件、多文件上传一般借助于js或者flash组件,今天就同大家一起看一下如何使用silverlight实现这个功能,而且功能和用户体验相对会更好一些。 主要内容: 一、组件特点 二、实现原理 三、编码实现 一、组件特点 对于今天要说的组件姑且叫做"CmjU

摘要:

文件上传是日常开过程中最常用的功能之一,目前实现文件上传的方式多种多样。这其中较为复杂的情况就是关于大文件、多文件上传的问题,目前解决大文件、多文件上传一般借助于Js或者flash组件,今天就同大家一起看一下如何使用silverlight实现这个功能,而且功能和用户体验相对会更好一些。

主要内容:

一、组件特点

二、实现原理

三、编码实现

一、组件特点

对于今天要说的组件姑且叫做"CmjUpload"吧,方便称呼。目前有很多上传组件来辅助完成日常开发,"CmjUpload"有什么特点呢:

解决大文件、多文件上传问题 基于asp.net上传,不需要部署WCF、WebService *** 作方便 接口丰富、灵活性强,配置使用方便。 支持选择、拖拽两种文件添加方式上传,用户体验好。 支持取消、暂停、继续 *** 作满足续传要求。

OK,就说那么多吧,主要是让大家有兴趣看下去,其实之所以有今天的话题主要还是为了学习以及满足实际开发需求。

二、实现原理

在Silverlight中要实现上传有很多方式,例如说使用WCF或者WebService,但是考虑到实际情况,这里没有选择以上两种方式,而是选择了WebRequest方式。原因比较简单,部署十分方便,不需要为了上传组件而进行额外的配置。Silverlight中使用WebRequest同其他.Net开发中的使用方式是类似的,不同的是Silverlight中很多 *** 作都是异步的,当然WebRequest也不例外。此外,在这里需要对一个文件分块发送,一方面可以解决大文件上传问题,另一方面可以实时显示文件上传进度。下面一个简单的交互过程:

 

当然要完成整个组件远不止上面说的这些,UI的设计,组件的本地化,用户接口的设计等都是必须思考的问题。下面是组件界面原型:

界面分为两个区域:文件显示区域和 *** 作区域,当然这里的文件区域本身也是可以 *** 作的,例如如果你不想点击按钮选择文件的话,可以选择直接拖拽一个或多个文件到文件区域。还可以对已添加的文件进行删除 *** 作,对正在上传的文件进行暂停和续传 *** 作。此外文件区域的设计主要提供文件信息显示,例如缩略图、上传进度、文件名称、文件大小等信息。 *** 作区域一方面提供文件整体信息的显示(例如文件总数、已上传数等),另一方面提供了文件浏览、上传、清空 *** 作。

下面是类的设计:

在上图中我们可以看出有三个包:Core、Config、Util。

Core是核心包,里面主要包括文件队列管理(fileQueue)、文件上传控制(fileUpload)、文件界面区域(fileArea)、文件大小单位转换(fileSize)、缩略图控制(fileIcon)。

Config是配置和接口包,主要包括组件设计级别常量(注意不是用户级别也不是开发级别,开发级别配置在接口中进行)(UploadConstant)、客户端开发接口(ExposeInterface)、本地化实现(Localization)、接口注册(ClIEntInteraction)。

Util包主要包括一些常用辅助类,主要包括xml *** 作(XmlHelper)、服务器端文件保存辅助类(CmjUpload)。

三、编码实现

有了上面的分析相信下面的实现就相当容易理解了,首先看一下文件上传类fileUpload:

using System;using System.Net;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.Text;using System.IO;using System.windows.Threading;using CmjUpload.Util;using CmjUpload.Config; namespace CmjUpload{    public class fileUpload    {        //开始上传        public delegate voID StartUploadHanler(object sender,EventArgs e);        public event StartUploadHanler StartUpload;        public voID OnStartUpload(object sender,EventArgs e)        {            if (StartUpload != null)            {                StartUpload(sender,e);            }        }         // 上传        public delegate voID UploadingHanler(object sender,ProgressArgs e);        public event UploadingHanler Uploading;        public voID OnUploading(object sender,ProgressArgs e)        {            if (Uploading != null)            {                Uploading(sender,e);            }        }         //上传结束        public delegate voID UploadCompletedHanler(object sender,EventArgs e);        public event UploadCompletedHanler UploadCompleted;        public voID OnUploadCompleted(object sender,EventArgs e)        {            if (UploadCompleted != null)            {                UploadCompleted(sender,e);            }        }          private string _requestUrl = "";        private string _filename = "";        private long _fileLength = 0;        private long _blockLength = 4096;//单次上传文件大小        private long _postedLength = 0;//已传输文件大小        private long _nextLength = 0;//下次传输的文件大小        private bool _firstUpload = true;        private BinaryReader _fileReader = null;         private UploadStatus _uploadStatus = UploadStatus.Start;         public fileInfo file        {            get;            set;        }         //public long PostedLength        //{        //    get        //    {        //        return _postedLength;        //    }        //    set        //    {        //        _postedLength = value;        //    }        //}         public UploadStatus Status        {            get            {                return _uploadStatus;            }            set            {                _uploadStatus = value;            }        }         public voID Upload(fileInfo file)        {            this.file = file;            //XmlHelper xmlHelper = new XmlHelper("Config/CmjUploadConfig.xml");            //_requestUrl=xmlHelper.GetAttibuteValue("Upload","RequestUrl");            _requestUrl = ExposeInterface.Instance().RequestUrl;            this._filename = this.file.name;            this._fileLength = this.file.Length;            this._blockLength = fileSize.GetLockSize(this._fileLength);            //this._postedLength = 0;            _fileReader = new BinaryReader(file.OpenRead());            //_uploadStatus = UploadStatus.Start;            if (_fileLength < _blockLength)            {                _nextLength = _fileLength;            }            else            {                _nextLength = _blockLength;            }            OnStartUpload(this,new EventArgs());             UploadInBlock();        }         public voID UploadInBlock()//上传一块数据        {            UriBuilder uriBuilder = new UriBuilder(new Uri(_requestUrl,UriKind.absolute));            uriBuilder.query = string.Format("filename={0}&status="+_uploadStatus,this._filename);            WebRequest request = WebRequest.Create(uriBuilder.Uri);            request.Method = "POST";            request.ContentType = "multipart/mixed";//注意这里            request.ContentLength = _nextLength;            if (_firstUpload)            {                _uploadStatus = UploadStatus.Uploading;                _firstUpload = false;            }            request.BeginGetRequestStream((IAsyncResult asyncResult) =>            {                WebRequest rqst = asyncResult.AsyncState as WebRequest;                Stream rqstStm = rqst.EndGetRequestStream(asyncResult);                 byte[] buffer = new byte[_blockLength];                     int size = _fileReader.Read(buffer,buffer.Length);                if(size>0)                {                    rqstStm.Write(buffer,size);                    rqstStm.Flush();                    _postedLength += size;                    if ((_fileLength - _postedLength) < _blockLength)                    {                        _nextLength = _fileLength-_postedLength;                    }                }                rqstStm.Close();                 rqst.BeginGetResponse((IAsyncResult ascResult) =>//开始数据传输                {                    OnUploading(this,new ProgressArgs() { Percent = ((double)_postedLength / (double)_fileLength) });                     WebRequest webRequest = ascResult.AsyncState as WebRequest;                    WebResponse webResponse = (WebResponse)webRequest.EndGetResponse(ascResult);                    StreamReader reader = new StreamReader(webResponse.GetResponseStream());                    string responsestring = reader.ReadToEnd();                    reader.Close();                    if (_postedLength >= _fileLength)                    {                        _uploadStatus = UploadStatus.Complelte;                    }                    if (_uploadStatus == UploadStatus.Uploading)                    {                        UploadInBlock();                    }                    //else if(_uploadStatus==UploadStatus.Cancel)                    //{                    //    return;                    //}                    else if (_uploadStatus==UploadStatus.Complelte)                    {                        _fileReader.Close();                        OnUploadCompleted(this,new EventArgs());                    }                },request);            },request);        }         /// <summary>        /// 继续上传        /// </summary>        /// <param name="filename"></param>        /// <param name="uploadedLength"></param>        //public static voID ContinueUplaod(string filename,long uploadedLength)        //{         //}    }     //上传进度参数    public class ProgressArgs:EventArgs    {        public double Percent        {            get;            set;        }    }     public enum UploadStatus    {        Start,Uploading,Cancel,Complelte    }}

在这个类中需要注意的是状态的控制,因为组件需要实现文件暂停、续传功能,并且每次请求时需要发送相应的 *** 作状态;另一点就是对外公开了三个事件,用于给UI提供进度支持和状态通知。

fileQueue管理整个文件队列,控制着界面UI、文件上传等信息:

using System;using System.Collections.Generic;using System.IO; namespace CmjUpload{    /// <summary>    /// 文件队列管理者    /// </summary>    public class fileQueue    {        private static object _lock = new object();        private static fileQueue _fileQueue = null;        private Dictionary<string,int> _fileIndexs = null;//文件同索引对应关系        private Dictionary<string,fileInfo> _files = null;        private Dictionary<string,fileArea> _fileAeas = null;        private Dictionary<string,fileUpload> _fileUploader = null;        private int index = 0;         private fileQueue()        {            _fileIndexs = new Dictionary<string,int>();            _files = new Dictionary<string,fileInfo>();            _fileAeas = new Dictionary<string,fileArea>();            _fileUploader = new Dictionary<string,fileUpload>();        }         public static fileQueue Instance()        {            lock (_lock)            {                if (_fileQueue == null)                {                    _fileQueue = new fileQueue();                }            }            return _fileQueue;        }         public voID Add(fileInfo file)        {            _fileIndexs.Add(file.name,index);            _files.Add(file.name,file);            fileArea fileAerea = new fileArea(file);            _fileAeas.Add(file.name,fileAerea);            ++index;        }         public voID Remove(string filename)        {            _fileIndexs.Remove(filename);            _files.Remove(filename);            _fileAeas.Remove(filename);            _fileUploader.Remove(filename);        }         public Dictionary<string,fileInfo> files        {            get            {                return _files;            }            set            {                _files = value;            }        }         public Dictionary<string,fileArea> fileAreas        {            get            {                return _fileAeas;            }            set            {                _fileAeas = value;            }        }         public Dictionary<string,fileUpload> fileUploader        {            get            {                return _fileUploader;            }            set            {                _fileUploader = value;            }        }         public int GetfileIndex(string filename)        {            int i=-1;            if (_fileIndexs.ContainsKey(filename))            {                i = _fileIndexs[filename];            }            return i;        }         public voID Clear()        {            string[] tempfilenames=new string[this.files.Count];            this.files.Keys.copyTo(tempfilenames,0);            foreach (string filename in tempfilenames)            {                this.Remove(filename);            }        }    }}

fileArea用于构建每个文件的UI展示:

using System;using System.Net;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.windows.Media.Imaging;using System.IO;using Cmj.MyWeb.MySilverlight.MyUserControl.button; namespace CmjUpload{    public class fileArea    {        private fileInfo _file = null;        //private int _number = 0;        private GrID _container = null;        private TextBlock _name = null;        private Image _thumnail = null;        private Progressbar _progress = null;        private TextBlock _size = null;        private TextBlock _percent = null;        private Cancel _cancel = null;        private Pause _pause = null;        private Play _continue = null;        private Check _complete = null;         public fileArea(fileInfo file)        {            _file = file;            //_number = number;            _container = new GrID();            _container.name = "fileArea_container_" + file.name;            _container.ColumnDeFinitions.Add(new ColumnDeFinition() { WIDth = new GrIDLength(60)});            _container.ColumnDeFinitions.Add(new ColumnDeFinition());            _container.ColumnDeFinitions.Add(new ColumnDeFinition() { WIDth=new GrIDLength(60)});            _container.ColumnDeFinitions.Add(new ColumnDeFinition() { WIDth = new GrIDLength(60) });            _container.Height = 50;             _thumnail = new Image();            _thumnail.name = "fileArea_thumnail_" + file.name;            _thumnail.Height = 40;            _thumnail.source = fileIcon.Instance().GetthumbnailImage(file);            _thumnail.VerticalAlignment = VerticalAlignment.Bottom;            _thumnail.HorizontalAlignment = HorizontalAlignment.Center;            GrID.SetColumn(_thumnail,0);                         _progress = new Progressbar();            _progress.name = "fileArea_progress_" + file.name;            _progress.Minimum = 0;            _progress.Maximum = 100;            _progress.Value = 0;            _progress.Height = 20;            _progress.VerticalAlignment = VerticalAlignment.Bottom;            //_progress.HorizontalAlignment = HorizontalAlignment.Center;            GrID.SetColumn(_progress,1);             _name = new TextBlock();            _name.name = "fileArea_name_" + file.name;            _name.Text = file.name;            _name.VerticalAlignment = VerticalAlignment.Bottom;            _name.HorizontalAlignment = HorizontalAlignment.left;            _name.margin = new Thickness(10,2);            GrID.SetColumn(_name,1);             _percent = new TextBlock();            _percent.name = "fileArea_percent_" + file.name;            _percent.VerticalAlignment = VerticalAlignment.Bottom;            _percent.HorizontalAlignment = HorizontalAlignment.Right;            _percent.margin = new Thickness(0,10,2);            GrID.SetColumn(_percent,1);             _size = new TextBlock();            _size.name = "fileArea_size_" + file.name;            _size.VerticalAlignment = VerticalAlignment.Bottom;            _size.HorizontalAlignment = HorizontalAlignment.Right;            GrID.SetColumn(_size,2);             _cancel = new Cancel();            _cancel.name = "fileArea_cancel_"+file.name;            _cancel.WIDth = 15;            _cancel.Height = 15;            _cancel.VerticalAlignment = VerticalAlignment.Bottom;            //_cancel.Click += new RoutedEventHandler(_cancel_Click);            GrID.SetColumn(_cancel,3);            _pause = new Pause();            _pause.name = "fileArea_pause_" + file.name;            _pause.WIDth = 15;            _pause.Height = 15;            _pause.VerticalAlignment = VerticalAlignment.Bottom;            _pause.Visibility = Visibility.Collapsed;            GrID.SetColumn(_pause,3);            _continue = new Play();            _continue.name = "fileArea_continue_" + file.name;            _continue.WIDth = 15;            _continue.Height = 15;            _continue.VerticalAlignment = VerticalAlignment.Bottom;            _continue.Visibility = Visibility.Collapsed;            GrID.SetColumn(_continue,3);            _complete = new Check();            _complete.name = "fileArea_complete_" + file.name;            _complete.WIDth = 18;            _complete.Height = 18;            _complete.VerticalAlignment = VerticalAlignment.Bottom;            _complete.Visibility = Visibility.Collapsed;            GrID.SetColumn(_complete,3);             _container.Children.Add(_thumnail);            _container.Children.Add(_progress);            _container.Children.Add(_size);            _container.Children.Add(_name);            _container.Children.Add(_percent);            _container.Children.Add(_cancel);            _container.Children.Add(_pause);            _container.Children.Add(_continue);            _container.Children.Add(_complete);         }        public GrID Container        {            get            {                return _container;            }            set            {                _container = value;            }        }         public TextBlock name        {            get            {                return _name;            }            set            {                _name = value;            }        }         public Image Thumnail        {            get            {                return _thumnail;            }            set            {                _thumnail = value;            }        }         public Progressbar Progress        {            get            {                return _progress;            }            set            {                _progress = value;            }        }         public TextBlock Size        {            get            {                return _size;            }            set            {                _size = value;            }        }         public TextBlock Percent        {            get            {                return _percent;            }            set            {                _percent = value;            }        }         public Cancel Cancel        {            get            {                return _cancel;            }            set            {                _cancel = value;            }        }         public Pause Pause        {            get            {                return _pause;            }            set            {                _pause = value;            }        }         public Play Continue        {            get            {                return _continue;            }            set            {                _continue = value;            }        }         public Check Complete        {            get            {                return _complete;            }            set            {                _complete = value;            }        }    }}

ExposeInterface用于向客户端调用提供 *** 作接口:

using System;using System.Net;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.Collections.Generic;using System.windows.browser; namespace CmjUpload.Config{    public class ExposeInterface    {        private static object _lock = new object();        private static ExposeInterface _exposeInterface = null;         private string _fileTypes = string.Empty;        private string _fileDialogFilter = string.Empty;        private long _limitSize = 0;        private int _limitCount = 0;         private ExposeInterface()        {        }         public static ExposeInterface Instance()        {            lock (_lock)            {                if (_exposeInterface == null)                {                    _exposeInterface = new ExposeInterface();                }            }            return _exposeInterface;        }         [ScriptableMember]        public string fileTypes //ex:*.jpg|*.gif        {            get            {                return _fileTypes;            }            set            {                _fileTypes = value;            }        }         [ScriptableMember]        public string fileDialogFilter        {            get            {                if (this._fileDialogFilter == string.Empty&&this._fileTypes!=string.Empty)                {                    string[] types = this._fileTypes.Split('|');                    string[] filters=new string[types.Length];                    for(int i=0;i<types.Length;++i)                    {                        filters[i] = "("+types[i] +")|"+ types[i];                    }                    _fileDialogFilter = string.Join("|",filters);                }                return _fileDialogFilter;            }            set            {                _fileDialogFilter = value;            }        }         [ScriptableMember]        public long limitSize//单位 MB        {            get            {                return _limitSize;            }            set            {                _limitSize = value;            }        }         [ScriptableMember]        public int limitCount        {            get            {                return _limitCount;            }            set            {                _limitCount = value;            }        }         [ScriptableMember]        public string RequestUrl        {            get;            set;        }         public List<string> GetfileExtensions()        {            List<string> extensions = new List<string>();            string[] types = this._fileTypes.Split(new char[] { '|' },StringSplitoptions.RemoveEmptyEntrIEs);            foreach(string type in types)            {                extensions.Add(type.Trimstart('*'));            }            return extensions;        }    }}

CmjUpload用于提供给服务器端进行文件 *** 作,服务端只需要简单调用其Save方法就可以进行文件保存:

using System;using System.Collections.Generic;using System.Web;using System.IO; namespace CmjUpload.Web.Util{    public class CmjUpload    {        public static voID Save(string relationPath)        {            string filename = httpContext.Current.Request["filename"];            Save(relationPath,filename);        }         public static voID Save(string relationPath,string outputname)        {            string status = httpContext.Current.Request["status"];            if (status == "Start")            {                using (fileStream fs = file.Create(Path.Combine(relationPath,outputname)))                {                    Savefile(httpContext.Current.Request.inputStream,fs);                }            }            else if (status == "Uploading")            {                using (fileStream fs = file.Open(Path.Combine(relationPath,outputname),fileMode.Append))                {                    Savefile(httpContext.Current.Request.inputStream,fs);                }            }            else if (status == "Completed")            {                httpContext.Current.Response.Write("{success:true}");            }        }         private static voID Savefile(Stream stream,fileStream fs)        {            byte[] buffer = new byte[4096];            int bytesRead;            while ((bytesRead = stream.Read(buffer,buffer.Length)) != 0)            {                fs.Write(buffer,bytesRead);            }        }    }}

OK,其他的代码就不再贴出了,看一下客户端如何使用吧。

为了方便使用客户端提供一个公用Js类CmjUpload.Js:

//注意要在控件加载完之后调用,建议放到插件onload事件中初始化(<param name="onLoad" value="pluginLoaded" />)var CmjUpload = function (options) {    var uploader = null;     if (options.hasOwnProperty("ID")) {//组件ID        uploader = document.getElementByID(options.ID);    } else {        alert("Please configure the ID attribute before use CmjUpload component!");        return;    }     if (options.hasOwnProperty("requestUrl")) {//请求的url        uploader.content.cmjUpload.RequestUrl = options.requestUrl;    } else {        alert("Please configure the requestUrl attribute before use CmjUpload component!");        return;    }     if (options.hasOwnProperty("fileTypes")) {//文件类型限制        uploader.content.cmjUpload.fileTypes = options.fileTypes;    }    if (options.hasOwnProperty("limitCount")) {//每批次上传的文件数        uploader.content.cmjUpload.limitCount = options.limitCount;    }    if (options.hasOwnProperty("limitSize")) {//单个文件大小限制        uploader.content.cmjUpload.limitSize = options.limitSize;    }}CmjUpload.prototype.onBeforefileUpload = function () {//单个文件上传之前执行     } CmjUpload.prototype.onfileUploading = function () { //单个文件上传时执行     } CmjUpload.prototype.onfileUploaded = function () {//单个文件上传完毕执行 } CmjUpload.prototype.onBatchUploaded = function () {//整个批次的文件上传完毕执行 }

然后在页面添加上传组件(本地化语言在param中进行配置):

<object ID="cmjUpload1" data="data:application/x-silverlight-2," type="application/x-silverlight-2" wIDth="100%" height="100%">    <param name="source" value="ClIEntBin/CmjUpload.xap"/>    <param name="onError" value="onSilverlightError" />    <param name="onLoad" value="pluginLoaded" /><!--注意这里,必须保证配置信息在页面加载之后执行-->    <param name="culture" value="en-US" /><!--注意这里本地化配置-->    <param name="uiculture" value="en-US" /><!--注意这里本地化配置-->    <param name="background" value="white" />    <param name="minRuntimeVersion" value="4.0.50826.0" />    <param name="autoUpgrade" value="true" />    <a href="http://go.microsoft.com/fwlink/?linkID=149156&v=4.0.50826.0" >        <img src="http://go.microsoft.com/fwlink/?linkID=161376" alt="Get Microsoft Silverlight" />    </a></object>

使用时在页面引用该类,进行ID和url等信息配置,具体的配置内容上面Js已经注释的很清楚,这里不再赘余。例如对页面做如下配置:

pluginLoaded=function(){    var upload = new CmjUpload({ ID: 'cmjUpload1',requestUrl: 'http://localhost:3407/Upload.aspx',fileTypes: '*.jpg|*.png|*.wmv|*.rar|*.iso',limitCount: 5,limitSize: 150 });}

后台文件执行文件保存 *** 作:

using System;using System.Collections.Generic;using System.linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.IO; namespace CmjUpload.Web{    public partial class Upload : System.Web.UI.Page    {        protected voID Page_Load(object sender,EventArgs e)        {            CmjUpload.Web.Util.CmjUpload.Save("f:\");        }    }}

下面是使用效果:

类型限制

大小限制

数量限制

删除一个文件

上传中

上传暂停

完成上传

手动清空(即使不手动清空继续上传文件会自动清空,清空 *** 作主要用于上传暂停后不需要上传的清空)

下面看看本地化设置为英文后的效果

我们通过修改limitCount来看一下大文件传输,好几个G的文件同时传输也没有问题

 

OK,最后附上组件下载,使用方法上面说的也比较清楚了。关于组件源代码就不再提供下载了,相信读完这篇文章要实现并不难,真正需要的话可以给我留言或发邮件KenshinCui@hotmail.com。

组件下载

作品采用知识共享署名 2.5 中国大陆许可协议进行许可,欢迎转载,演绎或用于商业目的。但转载请注明来自崔江涛(KenshinCui),并包含相关链接。
总结

以上是内存溢出为你收集整理的Silverlight之文件上传组件全部内容,希望文章能够帮你解决Silverlight之文件上传组件所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1071027.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存