使用 MultiUpload 和 ImageList 服务器控件进行专业文件上传
一个专业的 AJAX GUI,用于使用 Memba Velodoc XP Edition 中的服务器控件上传文件。
引言
ImageList 和 MultiUpload 最近在两篇文章中被介绍过
我们的目标是实现一个专业的 GUI 来上传文件,这通过结合 ImageList
和 MultiUpload
来实现。我们的环境是 ASP.NET 2.0 (Windows 和 IIS),我们的 ImageList
和 MultiUpload
控件都使用了 ASP.NET AJAX Extensions 1.0,您可以从此处下载并安装。
背景
本文引用了“Memba Velodoc XP Edition”的开源控件,您可以从此处下载(此页面提供 Codeplex、Google Code 和 Sourceforge.NET 的链接),它们以 GPL 许可分发。这些控件包括 ImageList
和 MultiUpload
控件,我们在本文中使用它们。您可以此链接现场体验这些控件。
使用代码
在 Visual Studio 2005 中,创建一个新的 ASP.NET AJAX 启用网站,并添加对 Memba.WebControls.XP.dll 的引用,其中包含 ImageList
和 MultiUpload2
服务器控件。Memba.WebControls.XP.dll 是 Memba Velodoc XP Edition 的一部分。源代码可在上述下载位置找到。
打开 Default.aspx 页面,并添加 ImageList
和 MultiUpload2
服务器控件,方法是将控件添加到工具箱后拖放,或者简单地在现有的 <form>
标签之间添加以下代码
<form id="form1" runat="server" enctype="multipart/form-data">
<asp:ScriptManager ID="ScriptManager" runat="server">
<Scripts>
<asp:ScriptReference Path="~/scripts/Memba.Utils.js" />
</Scripts>
</asp:ScriptManager>
<!-- MultiUpload2 -->
<mbui:MultiUpload2 ID="MultiUpload" runat="server"
Text="Choose file..."
Width="100px"
CssClass="cssMultiUpload"
HoverCssClass="cssMultiUploadHover">
</mbui:MultiUpload2>
<!-- MultiUpload2 -->
<!-- ImageList -->
<mbui:ImageList ID="ImageList" runat="server"
CssClass="cssList"
ItemCssClass="cssItem"
ItemHoverCssClass="cssItemHover"
ImageCssClass="cssImage"
TextCssClass="cssText"
RemoveCssClass="cssRemove"
RemoveTooltip="Remove from selection"
LinesOfText="2"
Height="92px"
Width="420px">
</mbui:ImageList>
<!-- ImageList -->
<input type="button" id="ClearButton" value="Clear" onclick="onClear();" />
<asp:Button ID="SubmitButton" runat="server" Text="Submit" OnClick="SubmitButton_Click" />
</form>
此表单还包括一个 HTML 按钮 (ClearButton
) 和一个 ASP.NET 提交按钮 (SubmitButton
)。
您可能需要在页面顶部使用以下语句注册标签前缀
<%@ Register Assembly="Memba.WebControls.XP"
Namespace="Memba.WebControls" TagPrefix="mbui" %>
请确保您添加了对 Memba.Utils.js 的脚本引用,其中包含创建 JavaScript GUID 所必需的实用函数。
为了使文件上传正常工作,您需要进行两项重要设置
- 在
form
标签上定义enctype="multipart/form-data"
; - 在 web.config 的
<system.web>
部分添加一个httpRuntime
部分。这在引言中引用的文章中有详细描述。
用于呈现 ImageList
和 MultiUpload
的内联 CSS 样式也在相应的文章中有描述。添加样式后,您的设计模式下的页面应如下所示
现在我们的页面已设计完成,我们需要代码来保存已发布的文件。双击提交按钮 (btnSubmit
) 以在 Default.aspx.cs 中实现服务器端 Click
事件处理程序
private const string TARGET_DIR = "~/";
protected void SubmitButton_Click(object sender, EventArgs e)
{
//Check target directory
string sTargetDir = Request.MapPath(TARGET_DIR);
System.Diagnostics.Debug.Assert(Directory.Exists(sTargetDir));
//Iterate through posted files
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFile objFile = Request.Files[i];
//Make sure file input has content
if ((objFile.ContentLength > 0) && (objFile.FileName.Length > 0))
{
//Get target file path for save as
string sFileName = Path.GetFileName(objFile.FileName);
string sFilePath = Path.Combine(sTargetDir, sFileName);
FileInfo objFileInfo = new FileInfo(sFilePath);
//No business rule, i.e. we just want to avoid failure
if (objFileInfo.Exists)
{
objFileInfo.Attributes &= ~FileAttributes.ReadOnly;
objFileInfo.Delete();
}
//Save file
objFile.SaveAs(sFilePath);
}
}
//Clear the list, otherwise the ImageList has items
//Which the MuliUpload component does not have
ImageList.ImageListItemCollection.Clear();
}
在文件顶部添加以下语句
using System.IO; //Directory, Path, FileInfo
这里需要注意的关键是,浏览器每次加载页面时都会清除 HTML 文件输入控件,尤其是在回发后。无法设置文件输入控件的值,否则 Web 服务器可以在未经用户同意的情况下获取用户文件。对此安全限制没有变通方法。我们的 ImageList
被设计为保持其状态,因此需要清除它以与 MultiUpload
控件同步。
此时我们可以运行页面并上传文件,但我们需要一些 JavaScript 客户端代码来在 ImageList
中显示已在 MultiUpload
控件中选择的文件。在页面的 </body>
结束标签之前添加以下脚本
<script type="text/javascript">
<!--
// Declare global variables for the various controls
var g_MultiUpload;
var g_ImageList;
//pageLoad function of ASP.NET Ajax Extensions framework
function pageLoad()
{
//Get a reference to the MultiUpload control and
//add en event handler for the browse event
g_MultiUpload = $find("<%= MultiUpload.ClientID %>");
if(g_MultiUpload)
g_MultiUpload.add_browse(onBrowse);
//Get a reference to the ImageList control and
//add en event handler for the browse event
g_ImageList = $find("<%= ImageList.ClientID %>");
if(g_ImageList)
g_ImageList.add_remove(onRemove);
}
//pageLoad function of ASP.NET Ajax Extensions framework
function pageUnload()
{
if(g_MultiUpload)
g_MultiUpload.remove_browse(onBrowse);
if(g_ImageList)
g_ImageList.remove_remove(onRemove);
}
//Event handler for the browse (click) event of the MultiUpload control
function onBrowse(sender, args)
{
if((g_ImageList) && (g_MultiUpload))
{
//Search for the item in the Imagelist
if (g_ImageList.find_item(args.get_value()).length > 0)
{
alert("file already in list");
//The item already exists,
//we can remove the duplicate INPUT in the MultiUpload control
g_MultiUpload.removeInput(args.get_id());
}
else
{
//Since the item is not found in the ImageList,
//create a new item
var item = new Memba.WebControls.ImageListItem(
Memba.Utils.newGuid(),
'<%= this.ResolveClientUrl("~/images/upload.gif") %>',
args.get_value(),
args.get_value(),
args.get_id()
);
//Add the new item to the ImageList
g_ImageList.add_item(item);
}
//We can do some tracing which will display in the TraceConsole textarea
Sys.Debug.trace(g_ImageList.get_count()
+ " files in image list, and " + g_MultiUpload.get_count()
+ " files in MultiUpload control");
}
}
//Event handler for the remove event of the ImageList control
function onRemove(sender, args)
{
if((g_ImageList) && (g_MultiUpload))
{
//Upon clicking the remove icon in the ImageList,
//remove the corresponding INPUT in the MultiUpload control
g_MultiUpload.removeInput(args.get_tag());
//We can do some tracing which will display in the TraceConsole textarea
Sys.Debug.trace(g_ImageList.get_count()
+ " files in image list, and " + g_MultiUpload.get_count()
+ " files in MultiUpload control");
}
}
//Event handler for the click event of the clear button
function onClear()
{
if(g_MultiUpload)
g_MultiUpload.clear();
if(g_ImageList)
g_ImageList.clear();
}
//-->
</script>
ASP.NET AJAX 扩展提供了两个重要的 JavaScript 事件处理程序
pageLoad
由框架在页面 DOM 和脚本加载并初始化时调用。这是一个获取控件引用和添加事件处理程序的理想位置。pageUnload
由框架在页面卸载时调用。建议在此阶段清除处理程序。
上面的脚本实现了 MultiUpload
控件的 Browse
事件、ImageList
控件的 Remove
事件以及 Clear 按钮的 Click
事件的处理程序。Browse
事件处理程序将选定的文件添加到 ImageList
。ImageList
项有一个名为 tag
的属性,该属性设置为 MultiUpload
控件中文件输入的标识符。Remove
事件处理程序读取从 ImageList
中移除的项的 tag
,以从 MultiUpload
控件中移除相应的文件输入。Clear
事件处理程序仅清除 ImageList
和 MultiUpload
控件。
按 F5 运行项目,然后单击标有“Choose file...”的 MultiUpload
控件将文件添加到列表中。将鼠标移到 ImageList
中相应的项上,以显示移除图标(一个红色的叉)。单击移除图标以从上传选择中移除相应的文件。添加更多文件。测试 Clear 按钮。添加文件并提交以上传文件。
此时,完成一个专业的上传页面将需要一个进度指示器。我们建议阅读使用 Ajax 显示 ASP.NET 服务器任务的进度。如果您想将所有这些控件结合在一起,我建议下载 Memba Velodoc XP Edition 的源代码和其中包含的开发者教程,这将帮助您进入下一个阶段。
关注点
这个 MultiUpload
控件隐藏了动态创建文件输入 HTML 控件的复杂性,并消除了对已选择上传文件的呈现的任何限制。与 ImageList
控件的结合是我们在此描述的一个绝佳的呈现选项,它比旧的、丑陋的文件输入控件有了巨大的改进。对于更高级的开发人员,ImageList
和 MultiUpload
控件的源代码可在 Codeplex、Google Code 和 Sourceforge.NET 上找到,并且进行了非常详细的注释。
历史
- 版本 1.0 - 日期 2007 年 12 月 20 日。