天天看點

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之檔案上傳元件

繼續閱讀