天天看点

Silverlight之文件上传组件

摘要:

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

主要内容:

一、组件特点

二、实现原理

三、编码实现

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

解决大文件、多文件上传问题

基于asp.net上传,不需要部署wcf、webservice操作方便

接口丰富、灵活性强,配置使用方便。

支持选择、拖拽两种文件添加方式上传,用户体验好。

支持取消、暂停、继续操作满足续传要求。

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

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

Silverlight之文件上传组件

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

Silverlight之文件上传组件

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

下面是类的设计:

Silverlight之文件上传组件

在上图中我们可以看出有三个包:core、config、util。

core是核心包,里面主要包括文件队列管理(filequeue)、文件上传控制(fileupload)、文件界面区域(filearea)、文件大小单位转换(filesize)、缩略图控制(fileicon)。

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

util包主要包括一些常用辅助类,主要包括xml操作(xmlhelper)、服务器端文件保存辅助类(cmjupload)。

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

<code>using</code> <code>system;</code>

<code>using</code> <code>system.net;</code>

<code>using</code> <code>system.windows;</code>

<code>using</code> <code>system.windows.controls;</code>

<code>using</code> <code>system.windows.documents;</code>

<code>using</code> <code>system.windows.ink;</code>

<code>using</code> <code>system.windows.input;</code>

<code>using</code> <code>system.windows.media;</code>

<code>using</code> <code>system.windows.media.animation;</code>

<code>using</code> <code>system.windows.shapes;</code>

<code>using</code> <code>system.text;</code>

<code>using</code> <code>system.io;</code>

<code>using</code> <code>system.windows.threading;</code>

<code>using</code> <code>cmjupload.util;</code>

<code>using</code> <code>cmjupload.config;</code>

<code>namespace</code> <code>cmjupload</code>

<code>{</code>

<code>    </code><code>public</code> <code>class</code> <code>fileupload</code>

<code>    </code><code>{</code>

<code>        </code><code>//开始上传</code>

<code>        </code><code>public</code> <code>delegate</code> <code>void</code> <code>startuploadhanler(</code><code>object</code> <code>sender,eventargs e);</code>

<code>        </code><code>public</code> <code>event</code> <code>startuploadhanler startupload;</code>

<code>        </code><code>public</code> <code>void</code> <code>onstartupload(</code><code>object</code> <code>sender, eventargs e)</code>

<code>        </code><code>{</code>

<code>            </code><code>if</code> <code>(startupload !=</code><code>null</code><code>)</code>

<code>            </code><code>{</code>

<code>                </code><code>startupload(sender, e);</code>

<code>            </code><code>}</code>

<code>        </code><code>}</code>

<code>        </code><code>// 上传</code>

<code>        </code><code>public</code> <code>delegate</code> <code>void</code> <code>uploadinghanler(</code><code>object</code> <code>sender, progressargs e);</code>

<code>        </code><code>public</code> <code>event</code> <code>uploadinghanler uploading;</code>

<code>        </code><code>public</code> <code>void</code> <code>onuploading(</code><code>object</code> <code>sender, progressargs e)</code>

<code>            </code><code>if</code> <code>(uploading !=</code><code>null</code><code>)</code>

<code>                </code><code>uploading(sender,e);</code>

<code>        </code><code>//上传结束</code>

<code>        </code><code>public</code> <code>delegate</code> <code>void</code> <code>uploadcompletedhanler(</code><code>object</code> <code>sender, eventargs e);</code>

<code>        </code><code>public</code> <code>event</code> <code>uploadcompletedhanler uploadcompleted;</code>

<code>        </code><code>public</code> <code>void</code> <code>onuploadcompleted(</code><code>object</code> <code>sender, eventargs e)</code>

<code>            </code><code>if</code> <code>(uploadcompleted !=</code><code>null</code><code>)</code>

<code>                </code><code>uploadcompleted(sender, e);</code>

<code>        </code><code>private</code> <code>string</code> <code>_requesturl =</code><code>""</code><code>;</code>

<code>        </code><code>private</code> <code>string</code> <code>_filename =</code><code>""</code><code>;</code>

<code>        </code><code>private</code> <code>long</code> <code>_filelength = 0;</code>

<code>        </code><code>private</code> <code>long</code> <code>_blocklength = 4096;</code><code>//单次上传文件大小</code>

<code>        </code><code>private</code> <code>long</code> <code>_postedlength = 0;</code><code>//已传输文件大小</code>

<code>        </code><code>private</code> <code>long</code> <code>_nextlength = 0;</code><code>//下次传输的文件大小</code>

<code>        </code><code>private</code> <code>bool</code> <code>_firstupload =</code><code>true</code><code>;</code>

<code>        </code><code>private</code> <code>binaryreader _filereader =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>uploadstatus _uploadstatus = uploadstatus.start;</code>

<code>        </code><code>public</code> <code>fileinfo file</code>

<code>            </code><code>get</code><code>;</code>

<code>            </code><code>set</code><code>;</code>

<code>        </code><code>//public long postedlength</code>

<code>        </code><code>//{</code>

<code>        </code><code>//    get</code>

<code>        </code><code>//    {</code>

<code>        </code><code>//        return _postedlength;</code>

<code>        </code><code>//    }</code>

<code>        </code><code>//    set</code>

<code>        </code><code>//        _postedlength = value;</code>

<code>        </code><code>//}</code>

<code>        </code><code>public</code> <code>uploadstatus status</code>

<code>            </code><code>get</code>

<code>                </code><code>return</code> <code>_uploadstatus;</code>

<code>            </code><code>set</code>

<code>                </code><code>_uploadstatus = value;</code>

<code>        </code><code>public</code> <code>void</code> <code>upload(fileinfo file)</code>

<code>            </code><code>this</code><code>.file = file;</code>

<code>            </code><code>//xmlhelper xmlhelper = new xmlhelper("config/cmjuploadconfig.xml");</code>

<code>            </code><code>//_requesturl=xmlhelper.getattibutevalue("upload", "requesturl");</code>

<code>            </code><code>_requesturl = exposeinterface.instance().requesturl;</code>

<code>            </code><code>this</code><code>._filename =</code><code>this</code><code>.file.name;</code>

<code>            </code><code>this</code><code>._filelength =</code><code>this</code><code>.file.length;</code>

<code>            </code><code>this</code><code>._blocklength = filesize.getlocksize(</code><code>this</code><code>._filelength);</code>

<code>            </code><code>//this._postedlength = 0;</code>

<code>            </code><code>_filereader =</code><code>new</code> <code>binaryreader(file.openread());</code>

<code>            </code><code>//_uploadstatus = uploadstatus.start;</code>

<code>            </code><code>if</code> <code>(_filelength &lt; _blocklength)</code>

<code>                </code><code>_nextlength = _filelength;</code>

<code>            </code><code>else</code>

<code>                </code><code>_nextlength = _blocklength;</code>

<code>            </code><code>onstartupload(</code><code>this</code><code>,</code><code>new</code> <code>eventargs());</code>

<code>            </code><code>uploadinblock();</code>

<code>        </code><code>public</code> <code>void</code> <code>uploadinblock()</code><code>//上传一块数据</code>

<code>            </code><code>uribuilder uribuilder =</code><code>new</code> <code>uribuilder(</code><code>new</code> <code>uri(_requesturl, urikind.absolute));</code>

<code>            </code><code>uribuilder.query =</code><code>string</code><code>.format(</code><code>"filename={0}&amp;status="</code><code>+_uploadstatus,</code><code>this</code><code>._filename);</code>

<code>            </code><code>webrequest request = webrequest.create(uribuilder.uri);</code>

<code>            </code><code>request.method =</code><code>"post"</code><code>;</code>

<code>            </code><code>request.contenttype =</code><code>"multipart/mixed"</code><code>;</code><code>//注意这里</code>

<code>            </code><code>request.contentlength = _nextlength;</code>

<code>            </code><code>if</code> <code>(_firstupload)</code>

<code>                </code><code>_uploadstatus = uploadstatus.uploading;</code>

<code>                </code><code>_firstupload =</code><code>false</code><code>;</code>

<code>            </code><code>request.begingetrequeststream((iasyncresult asyncresult) =&gt;</code>

<code>                </code><code>webrequest rqst = asyncresult.asyncstate</code><code>as</code> <code>webrequest;</code>

<code>                </code><code>stream rqststm = rqst.endgetrequeststream(asyncresult);</code>

<code>                </code><code>byte</code><code>[] buffer =</code><code>new</code> <code>byte</code><code>[_blocklength];</code>

<code>    </code> 

<code>                </code><code>int</code> <code>size = _filereader.read(buffer, 0, buffer.length);</code>

<code>                </code><code>if</code><code>(size&gt;0)</code>

<code>                </code><code>{</code>

<code>                    </code><code>rqststm.write(buffer, 0, size);</code>

<code>                    </code><code>rqststm.flush();</code>

<code>                    </code><code>_postedlength += size;</code>

<code>                    </code><code>if</code> <code>((_filelength - _postedlength) &lt; _blocklength)</code>

<code>                    </code><code>{</code>

<code>                        </code><code>_nextlength = _filelength-_postedlength;</code>

<code>                    </code><code>}</code>

<code>                </code><code>}</code>

<code>                </code><code>rqststm.close();</code>

<code>                </code><code>rqst.begingetresponse((iasyncresult ascresult) =&gt;</code><code>//开始数据传输</code>

<code>                    </code><code>onuploading(</code><code>this</code><code>,</code><code>new</code> <code>progressargs() { percent = ((</code><code>double</code><code>)_postedlength / (</code><code>double</code><code>)_filelength) });</code>

<code>                    </code><code>webrequest webrequest = ascresult.asyncstate</code><code>as</code> <code>webrequest;</code>

<code>                    </code><code>webresponse webresponse = (webresponse)webrequest.endgetresponse(ascresult);</code>

<code>                    </code><code>streamreader reader =</code><code>new</code> <code>streamreader(webresponse.getresponsestream());</code>

<code>                    </code><code>string</code> <code>responsestring = reader.readtoend();</code>

<code>                    </code><code>reader.close();</code>

<code>                    </code><code>if</code> <code>(_postedlength &gt;= _filelength)</code>

<code>                        </code><code>_uploadstatus = uploadstatus.complelte;</code>

<code>                    </code><code>if</code> <code>(_uploadstatus == uploadstatus.uploading)</code>

<code>                        </code><code>uploadinblock();</code>

<code>                    </code><code>//else if(_uploadstatus==uploadstatus.cancel)</code>

<code>                    </code><code>//{</code>

<code>                    </code><code>//    return;</code>

<code>                    </code><code>//}</code>

<code>                    </code><code>else</code> <code>if</code> <code>(_uploadstatus==uploadstatus.complelte)</code>

<code>                        </code><code>_filereader.close();</code>

<code>                        </code><code>onuploadcompleted(</code><code>this</code><code>,</code><code>new</code> <code>eventargs());</code>

<code>                </code><code>}, request);</code>

<code>            </code><code>}, request);</code>

<code>        </code><code>/// &lt;summary&gt;</code>

<code>        </code><code>/// 继续上传</code>

<code>        </code><code>/// &lt;/summary&gt;</code>

<code>        </code><code>/// &lt;param name="filename"&gt;&lt;/param&gt;</code>

<code>        </code><code>/// &lt;param name="uploadedlength"&gt;&lt;/param&gt;</code>

<code>        </code><code>//public static void continueuplaod(string filename,long uploadedlength)</code>

<code>    </code><code>}</code>

<code>    </code><code>//上传进度参数</code>

<code>    </code><code>public</code> <code>class</code> <code>progressargs:eventargs</code>

<code>        </code><code>public</code> <code>double</code> <code>percent</code>

<code>    </code><code>public</code> <code>enum</code> <code>uploadstatus</code>

<code>        </code><code>start,</code>

<code>        </code><code>uploading,</code>

<code>        </code><code>cancel,</code>

<code>        </code><code>complelte</code>

<code>}</code>

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

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

<code>using</code> <code>system.collections.generic;</code>

<code>    </code><code>/// &lt;summary&gt;</code>

<code>    </code><code>/// 文件队列管理者</code>

<code>    </code><code>/// &lt;/summary&gt;</code>

<code>    </code><code>public</code> <code>class</code> <code>filequeue</code>

<code>        </code><code>private</code> <code>static</code> <code>object</code> <code>_lock =</code><code>new</code> <code>object</code><code>();</code>

<code>        </code><code>private</code> <code>static</code> <code>filequeue _filequeue =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>dictionary&lt;</code><code>string</code><code>,</code><code>int</code><code>&gt; _fileindexs =</code><code>null</code><code>;</code><code>//文件同索引对应关系</code>

<code>        </code><code>private</code> <code>dictionary&lt;</code><code>string</code><code>,fileinfo&gt; _files =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>dictionary&lt;</code><code>string</code><code>,filearea&gt; _fileaeas =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>dictionary&lt;</code><code>string</code><code>, fileupload&gt; _fileuploader =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>int</code> <code>index = 0;</code>

<code>        </code><code>private</code> <code>filequeue()</code>

<code>            </code><code>_fileindexs =</code><code>new</code> <code>dictionary&lt;</code><code>string</code><code>,</code><code>int</code><code>&gt;();</code>

<code>            </code><code>_files =</code><code>new</code> <code>dictionary&lt;</code><code>string</code><code>, fileinfo&gt;();</code>

<code>            </code><code>_fileaeas =</code><code>new</code> <code>dictionary&lt;</code><code>string</code><code>, filearea&gt;();</code>

<code>            </code><code>_fileuploader =</code><code>new</code> <code>dictionary&lt;</code><code>string</code><code>, fileupload&gt;();</code>

<code>        </code><code>public</code> <code>static</code> <code>filequeue instance()</code>

<code>            </code><code>lock</code> <code>(_lock)</code>

<code>                </code><code>if</code> <code>(_filequeue ==</code><code>null</code><code>)</code>

<code>                    </code><code>_filequeue =</code><code>new</code> <code>filequeue();</code>

<code>            </code><code>return</code> <code>_filequeue;</code>

<code>        </code><code>public</code> <code>void</code> <code>add(fileinfo file)</code>

<code>            </code><code>_fileindexs.add(file.name, index);</code>

<code>            </code><code>_files.add(file.name,file);</code>

<code>            </code><code>filearea fileaerea =</code><code>new</code> <code>filearea(file);</code>

<code>            </code><code>_fileaeas.add(file.name, fileaerea);</code>

<code>            </code><code>++index;</code>

<code>        </code><code>public</code> <code>void</code> <code>remove(</code><code>string</code> <code>filename)</code>

<code>            </code><code>_fileindexs.remove(filename);</code>

<code>            </code><code>_files.remove(filename);</code>

<code>            </code><code>_fileaeas.remove(filename);</code>

<code>            </code><code>_fileuploader.remove(filename);</code>

<code>        </code><code>public</code> <code>dictionary&lt;</code><code>string</code><code>,fileinfo&gt; files</code>

<code>                </code><code>return</code> <code>_files;</code>

<code>                </code><code>_files = value;</code>

<code>        </code><code>public</code> <code>dictionary&lt;</code><code>string</code><code>, filearea&gt; fileareas</code>

<code>                </code><code>return</code> <code>_fileaeas;</code>

<code>                </code><code>_fileaeas = value;</code>

<code>        </code><code>public</code> <code>dictionary&lt;</code><code>string</code><code>, fileupload&gt; fileuploader</code>

<code>                </code><code>return</code> <code>_fileuploader;</code>

<code>                </code><code>_fileuploader = value;</code>

<code>        </code><code>public</code> <code>int</code> <code>getfileindex(</code><code>string</code> <code>filename)</code>

<code>            </code><code>int</code> <code>i=-1;</code>

<code>            </code><code>if</code> <code>(_fileindexs.containskey(filename))</code>

<code>                </code><code>i = _fileindexs[filename];</code>

<code>            </code><code>return</code> <code>i;</code>

<code>        </code><code>public</code> <code>void</code> <code>clear()</code>

<code>            </code><code>string</code><code>[] tempfilenames=</code><code>new</code> <code>string</code><code>[</code><code>this</code><code>.files.count];</code>

<code>            </code><code>this</code><code>.files.keys.copyto(tempfilenames,0);</code>

<code>            </code><code>foreach</code> <code>(</code><code>string</code> <code>filename</code><code>in</code> <code>tempfilenames)</code>

<code>                </code><code>this</code><code>.remove(filename);</code>

filearea用于构建每个文件的ui展示:

<code>using</code> <code>system.windows.media.imaging;</code>

<code>using</code> <code>cmj.myweb.mysilverlight.myusercontrol.button;</code>

<code>    </code><code>public</code> <code>class</code> <code>filearea</code>

<code>        </code><code>private</code> <code>fileinfo _file =</code><code>null</code><code>;</code>

<code>        </code><code>//private int _number = 0;</code>

<code>        </code><code>private</code> <code>grid _container =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>textblock _name =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>image _thumnail =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>progressbar _progress =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>textblock _size =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>textblock _percent =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>cancel _cancel =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>pause _pause =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>play _continue =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>check _complete =</code><code>null</code><code>;</code>

<code>        </code><code>public</code> <code>filearea(fileinfo file)</code>

<code>            </code><code>_file = file;</code>

<code>            </code><code>//_number = number;</code>

<code>            </code><code>_container =</code><code>new</code> <code>grid();</code>

<code>            </code><code>_container.name =</code><code>"filearea_container_"</code> <code>+ file.name;</code>

<code>            </code><code>_container.columndefinitions.add(</code><code>new</code> <code>columndefinition() { width =</code><code>new</code> <code>gridlength(60)});</code>

<code>            </code><code>_container.columndefinitions.add(</code><code>new</code> <code>columndefinition());</code>

<code>            </code><code>_container.columndefinitions.add(</code><code>new</code> <code>columndefinition() { width=</code><code>new</code> <code>gridlength(60)});</code>

<code>            </code><code>_container.columndefinitions.add(</code><code>new</code> <code>columndefinition() { width =</code><code>new</code> <code>gridlength(60) });</code>

<code>            </code><code>_container.height = 50;</code>

<code>            </code><code>_thumnail =</code><code>new</code> <code>image();</code>

<code>            </code><code>_thumnail.name =</code><code>"filearea_thumnail_"</code> <code>+ file.name;</code>

<code>            </code><code>_thumnail.height = 40;</code>

<code>            </code><code>_thumnail.source = fileicon.instance().getthumbnailimage(file);</code>

<code>            </code><code>_thumnail.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_thumnail.horizontalalignment = horizontalalignment.center;</code>

<code>            </code><code>grid.setcolumn(_thumnail, 0);</code>

<code>            </code> 

<code>            </code><code>_progress =</code><code>new</code> <code>progressbar();</code>

<code>            </code><code>_progress.name =</code><code>"filearea_progress_"</code> <code>+ file.name;</code>

<code>            </code><code>_progress.minimum = 0;</code>

<code>            </code><code>_progress.maximum = 100;</code>

<code>            </code><code>_progress.value = 0;</code>

<code>            </code><code>_progress.height = 20;</code>

<code>            </code><code>_progress.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>//_progress.horizontalalignment = horizontalalignment.center;</code>

<code>            </code><code>grid.setcolumn(_progress, 1);</code>

<code>            </code><code>_name =</code><code>new</code> <code>textblock();</code>

<code>            </code><code>_name.name =</code><code>"filearea_name_"</code> <code>+ file.name;</code>

<code>            </code><code>_name.text = file.name;</code>

<code>            </code><code>_name.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_name.horizontalalignment = horizontalalignment.left;</code>

<code>            </code><code>_name.margin =</code><code>new</code> <code>thickness(10, 0, 0, 2);</code>

<code>            </code><code>grid.setcolumn(_name, 1);</code>

<code>            </code><code>_percent =</code><code>new</code> <code>textblock();</code>

<code>            </code><code>_percent.name =</code><code>"filearea_percent_"</code> <code>+ file.name;</code>

<code>            </code><code>_percent.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_percent.horizontalalignment = horizontalalignment.right;</code>

<code>            </code><code>_percent.margin =</code><code>new</code> <code>thickness(0, 0, 10, 2);</code>

<code>            </code><code>grid.setcolumn(_percent, 1);</code>

<code>            </code><code>_size =</code><code>new</code> <code>textblock();</code>

<code>            </code><code>_size.name =</code><code>"filearea_size_"</code> <code>+ file.name;</code>

<code>            </code><code>_size.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_size.horizontalalignment = horizontalalignment.right;</code>

<code>            </code><code>grid.setcolumn(_size, 2);</code>

<code>            </code><code>_cancel =</code><code>new</code> <code>cancel();</code>

<code>            </code><code>_cancel.name =</code><code>"filearea_cancel_"</code><code>+file.name;</code>

<code>            </code><code>_cancel.width = 15;</code>

<code>            </code><code>_cancel.height = 15;</code>

<code>            </code><code>_cancel.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>//_cancel.click += new routedeventhandler(_cancel_click);</code>

<code>            </code><code>grid.setcolumn(_cancel, 3);</code>

<code>            </code><code>_pause =</code><code>new</code> <code>pause();</code>

<code>            </code><code>_pause.name =</code><code>"filearea_pause_"</code> <code>+ file.name;</code>

<code>            </code><code>_pause.width = 15;</code>

<code>            </code><code>_pause.height = 15;</code>

<code>            </code><code>_pause.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_pause.visibility = visibility.collapsed;</code>

<code>            </code><code>grid.setcolumn(_pause, 3);</code>

<code>            </code><code>_continue =</code><code>new</code> <code>play();</code>

<code>            </code><code>_continue.name =</code><code>"filearea_continue_"</code> <code>+ file.name;</code>

<code>            </code><code>_continue.width = 15;</code>

<code>            </code><code>_continue.height = 15;</code>

<code>            </code><code>_continue.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_continue.visibility = visibility.collapsed;</code>

<code>            </code><code>grid.setcolumn(_continue, 3);</code>

<code>            </code><code>_complete =</code><code>new</code> <code>check();</code>

<code>            </code><code>_complete.name =</code><code>"filearea_complete_"</code> <code>+ file.name;</code>

<code>            </code><code>_complete.width = 18;</code>

<code>            </code><code>_complete.height = 18;</code>

<code>            </code><code>_complete.verticalalignment = verticalalignment.bottom;</code>

<code>            </code><code>_complete.visibility = visibility.collapsed;</code>

<code>            </code><code>grid.setcolumn(_complete, 3);</code>

<code>            </code><code>_container.children.add(_thumnail);</code>

<code>            </code><code>_container.children.add(_progress);</code>

<code>            </code><code>_container.children.add(_size);</code>

<code>            </code><code>_container.children.add(_name);</code>

<code>            </code><code>_container.children.add(_percent);</code>

<code>            </code><code>_container.children.add(_cancel);</code>

<code>            </code><code>_container.children.add(_pause);</code>

<code>            </code><code>_container.children.add(_continue);</code>

<code>            </code><code>_container.children.add(_complete);</code>

<code>        </code><code>public</code> <code>grid container</code>

<code>                </code><code>return</code> <code>_container;</code>

<code>                </code><code>_container = value;</code>

<code>        </code><code>public</code> <code>textblock name</code>

<code>                </code><code>return</code> <code>_name;</code>

<code>                </code><code>_name = value;</code>

<code>        </code><code>public</code> <code>image thumnail</code>

<code>                </code><code>return</code> <code>_thumnail;</code>

<code>                </code><code>_thumnail = value;</code>

<code>        </code><code>public</code> <code>progressbar progress</code>

<code>                </code><code>return</code> <code>_progress;</code>

<code>                </code><code>_progress = value;</code>

<code>        </code><code>public</code> <code>textblock size</code>

<code>                </code><code>return</code> <code>_size;</code>

<code>                </code><code>_size = value;</code>

<code>        </code><code>public</code> <code>textblock percent</code>

<code>                </code><code>return</code> <code>_percent;</code>

<code>                </code><code>_percent = value;</code>

<code>        </code><code>public</code> <code>cancel cancel</code>

<code>                </code><code>return</code> <code>_cancel;</code>

<code>                </code><code>_cancel = value;</code>

<code>        </code><code>public</code> <code>pause pause</code>

<code>                </code><code>return</code> <code>_pause;</code>

<code>                </code><code>_pause = value;</code>

<code>        </code><code>public</code> <code>play continue</code>

<code>                </code><code>return</code> <code>_continue;</code>

<code>                </code><code>_continue = value;</code>

<code>        </code><code>public</code> <code>check complete</code>

<code>                </code><code>return</code> <code>_complete;</code>

<code>                </code><code>_complete = value;</code>

exposeinterface用于向客户端调用提供操作接口:

<code>using</code> <code>system.windows.browser;</code>

<code>namespace</code> <code>cmjupload.config</code>

<code>    </code><code>public</code> <code>class</code> <code>exposeinterface</code>

<code>        </code><code>private</code> <code>static</code> <code>exposeinterface _exposeinterface =</code><code>null</code><code>;</code>

<code>        </code><code>private</code> <code>string</code> <code>_filetypes =</code><code>string</code><code>.empty;</code>

<code>        </code><code>private</code> <code>string</code> <code>_filedialogfilter =</code><code>string</code><code>.empty;</code>

<code>        </code><code>private</code> <code>long</code> <code>_limitsize = 0;</code>

<code>        </code><code>private</code> <code>int</code> <code>_limitcount = 0;</code>

<code>        </code><code>private</code> <code>exposeinterface()</code>

<code>        </code><code>public</code> <code>static</code> <code>exposeinterface instance()</code>

<code>                </code><code>if</code> <code>(_exposeinterface ==</code><code>null</code><code>)</code>

<code>                    </code><code>_exposeinterface =</code><code>new</code> <code>exposeinterface();</code>

<code>            </code><code>return</code> <code>_exposeinterface;</code>

<code>        </code><code>[scriptablemember]</code>

<code>        </code><code>public</code> <code>string</code> <code>filetypes</code><code>//ex:*.jpg|*.gif</code>

<code>                </code><code>return</code> <code>_filetypes;</code>

<code>                </code><code>_filetypes = value;</code>

<code>        </code><code>public</code> <code>string</code> <code>filedialogfilter</code>

<code>                </code><code>if</code> <code>(</code><code>this</code><code>._filedialogfilter ==</code><code>string</code><code>.empty&amp;&amp;</code><code>this</code><code>._filetypes!=</code><code>string</code><code>.empty)</code>

<code>                    </code><code>string</code><code>[] types =</code><code>this</code><code>._filetypes.split(</code><code>'|'</code><code>);</code>

<code>                    </code><code>string</code><code>[] filters=</code><code>new</code> <code>string</code><code>[types.length];</code>

<code>                    </code><code>for</code><code>(</code><code>int</code> <code>i=0;i&lt;types.length;++i)</code>

<code>                        </code><code>filters[i] =</code><code>"("</code><code>+types[i] +</code><code>")|"</code><code>+ types[i];</code>

<code>                    </code><code>_filedialogfilter =</code><code>string</code><code>.join(</code><code>"|"</code><code>,filters);</code>

<code>                </code><code>return</code> <code>_filedialogfilter;</code>

<code>                </code><code>_filedialogfilter = value;</code>

<code>        </code><code>public</code> <code>long</code> <code>limitsize</code><code>//单位 mb</code>

<code>                </code><code>return</code> <code>_limitsize;</code>

<code>                </code><code>_limitsize = value;</code>

<code>        </code><code>public</code> <code>int</code> <code>limitcount</code>

<code>                </code><code>return</code> <code>_limitcount;</code>

<code>                </code><code>_limitcount = value;</code>

<code>        </code><code>public</code> <code>string</code> <code>requesturl</code>

<code>        </code><code>public</code> <code>list&lt;</code><code>string</code><code>&gt; getfileextensions()</code>

<code>            </code><code>list&lt;</code><code>string</code><code>&gt; extensions =</code><code>new</code> <code>list&lt;</code><code>string</code><code>&gt;();</code>

<code>            </code><code>string</code><code>[] types =</code><code>this</code><code>._filetypes.split(</code><code>new</code> <code>char</code><code>[] {</code><code>'|'</code> <code>}, stringsplitoptions.removeemptyentries);</code>

<code>            </code><code>foreach</code><code>(</code><code>string</code> <code>type</code><code>in</code> <code>types)</code>

<code>                </code><code>extensions.add(type.trimstart(</code><code>'*'</code><code>));</code>

<code>            </code><code>return</code> <code>extensions;</code>

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

<code>using</code> <code>system.web;</code>

<code>namespace</code> <code>cmjupload.web.util</code>

<code>    </code><code>public</code> <code>class</code> <code>cmjupload</code>

<code>        </code><code>public</code> <code>static</code> <code>void</code> <code>save(</code><code>string</code> <code>relationpath)</code>

<code>            </code><code>string</code> <code>filename = httpcontext.current.request[</code><code>"filename"</code><code>];</code>

<code>            </code><code>save(relationpath,filename);</code>

<code>        </code><code>public</code> <code>static</code> <code>void</code> <code>save(</code><code>string</code> <code>relationpath,</code><code>string</code> <code>outputname)</code>

<code>            </code><code>string</code> <code>status = httpcontext.current.request[</code><code>"status"</code><code>];</code>

<code>            </code><code>if</code> <code>(status ==</code><code>"start"</code><code>)</code>

<code>                </code><code>using</code> <code>(filestream fs = file.create(path.combine(relationpath, outputname)))</code>

<code>                    </code><code>savefile(httpcontext.current.request.inputstream, fs);</code>

<code>            </code><code>else</code> <code>if</code> <code>(status ==</code><code>"uploading"</code><code>)</code>

<code>                </code><code>using</code> <code>(filestream fs = file.open(path.combine(relationpath, outputname), filemode.append))</code>

<code>            </code><code>else</code> <code>if</code> <code>(status ==</code><code>"completed"</code><code>)</code>

<code>                </code><code>httpcontext.current.response.write(</code><code>"{success:true}"</code><code>);</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>savefile(stream stream, filestream fs)</code>

<code>            </code><code>byte</code><code>[] buffer =</code><code>new</code> <code>byte</code><code>[4096];</code>

<code>            </code><code>int</code> <code>bytesread;</code>

<code>            </code><code>while</code> <code>((bytesread = stream.read(buffer, 0, buffer.length)) != 0)</code>

<code>                </code><code>fs.write(buffer, 0, bytesread);</code>

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

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

<code>//注意要在控件加载完之后调用,建议放到插件onload事件中初始化(&lt;param name="onload" value="pluginloaded" /&gt;)</code>

<code>var</code> <code>cmjupload =</code><code>function</code> <code>(options) {</code>

<code>    </code><code>var</code> <code>uploader =</code><code>null</code><code>;</code>

<code>    </code><code>if</code> <code>(options.hasownproperty(</code><code>"id"</code><code>)) {</code><code>//组件id</code>

<code>        </code><code>uploader = document.getelementbyid(options.id);</code>

<code>    </code><code>}</code><code>else</code> <code>{</code>

<code>        </code><code>alert(</code><code>"please configure the id attribute before use cmjupload component!"</code><code>);</code>

<code>        </code><code>return</code><code>;</code>

<code>    </code><code>if</code> <code>(options.hasownproperty(</code><code>"requesturl"</code><code>)) {</code><code>//请求的url</code>

<code>        </code><code>uploader.content.cmjupload.requesturl = options.requesturl;</code>

<code>        </code><code>alert(</code><code>"please configure the requesturl attribute before use cmjupload component!"</code><code>);</code>

<code>    </code><code>if</code> <code>(options.hasownproperty(</code><code>"filetypes"</code><code>)) {</code><code>//文件类型限制</code>

<code>        </code><code>uploader.content.cmjupload.filetypes = options.filetypes;</code>

<code>    </code><code>if</code> <code>(options.hasownproperty(</code><code>"limitcount"</code><code>)) {</code><code>//每批次上传的文件数</code>

<code>        </code><code>uploader.content.cmjupload.limitcount = options.limitcount;</code>

<code>    </code><code>if</code> <code>(options.hasownproperty(</code><code>"limitsize"</code><code>)) {</code><code>//单个文件大小限制</code>

<code>        </code><code>uploader.content.cmjupload.limitsize = options.limitsize;</code>

<code>cmjupload.prototype.onbeforefileupload =</code><code>function</code> <code>() {</code><code>//单个文件上传之前执行</code>

<code>cmjupload.prototype.onfileuploading =</code><code>function</code> <code>() {</code><code>//单个文件上传时执行</code>

<code>cmjupload.prototype.onfileuploaded =</code><code>function</code> <code>() {</code><code>//单个文件上传完毕执行</code>

<code>cmjupload.prototype.onbatchuploaded =</code><code>function</code> <code>() {</code><code>//整个批次的文件上传完毕执行</code>

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

<code>&lt;</code><code>object</code> <code>id="cmjupload1" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="source" value="clientbin/cmjupload.xap"/&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="onerror" value="onsilverlighterror" /&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="onload" value="pluginloaded" /&gt;</code><code>&lt;!--注意这里,必须保证配置信息在页面加载之后执行--&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="culture" value="en-us" /&gt;</code><code>&lt;!--注意这里本地化配置--&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="uiculture" value="en-us" /&gt;</code><code>&lt;!--注意这里本地化配置--&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="background" value="white" /&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="minruntimeversion" value="4.0.50826.0" /&gt;</code>

<code>    </code><code>&lt;</code><code>param</code> <code>name="autoupgrade" value="true" /&gt;</code>

<code>    </code><code>&lt;/</code><code>a</code><code>&gt;</code>

<code>&lt;/</code><code>object</code><code>&gt;</code>

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

<code>pluginloaded=</code><code>function</code><code>(){</code>

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

<code>using</code> <code>system.linq;</code>

<code>using</code> <code>system.web.ui;</code>

<code>using</code> <code>system.web.ui.webcontrols;</code>

<code>namespace</code> <code>cmjupload.web</code>

<code>    </code><code>public</code> <code>partial</code> <code>class</code> <code>upload : system.web.ui.page</code>

<code>        </code><code>protected</code> <code>void</code> <code>page_load(</code><code>object</code> <code>sender, eventargs e)</code>

<code>            </code><code>cmjupload.web.util.cmjupload.save(</code><code>"f:\\"</code><code>);</code>

下面是使用效果:

类型限制

Silverlight之文件上传组件

大小限制

Silverlight之文件上传组件

数量限制

Silverlight之文件上传组件

删除一个文件

Silverlight之文件上传组件

上传中

Silverlight之文件上传组件

上传暂停

Silverlight之文件上传组件

完成上传

Silverlight之文件上传组件

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

Silverlight之文件上传组件

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

Silverlight之文件上传组件

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

Silverlight之文件上传组件
Silverlight之文件上传组件

继续阅读