以前寫過一篇《單頁面多類型的多附件上傳》的文章,但是在實際項目中,這樣的並不多見,相比之下,多附件上傳卻經常用到。 而每次使用都要複製粘貼相關的代碼,雖然不麻煩,但用起來卻不太方便,一旦忘記某段代碼沒複製過來,頁面就會報錯。 於是,就想把現在用的這些代碼,變成一個用戶自定義控制項,這樣再次使用的時候就 ...
以前寫過一篇《單頁面多類型的多附件上傳》的文章,但是在實際項目中,這樣的並不多見,相比之下,多附件上傳卻經常用到。
而每次使用都要複製粘貼相關的代碼,雖然不麻煩,但用起來卻不太方便,一旦忘記某段代碼沒複製過來,頁面就會報錯。
於是,就想把現在用的這些代碼,變成一個用戶自定義控制項,這樣再次使用的時候就方便多了。
話不多說,先看下界面吧。
設計時
運行後
先介紹下控制項界面,上下一共有兩個repeater,分別用於編輯和查看時使用。上面的repeater,帶有刪除按鈕,用於編輯時可以刪除不需要的附件;下麵的repeater,用於查看時使用,如果沒有上傳附件,則後臺代碼會給控制項Literal賦值空格符( ),用於解決瀏覽器相容問題(因為有些瀏覽器在表格行沒有數據時,邊框線不顯示)。
中間的上傳控制項,不用多說,用於上傳附件;後面的“添加”按鈕,點擊後,會調用JS代碼動態創建上傳控制項,以便能夠上傳多個附件;下麵的隱藏控制項,前期用於記錄創建的上傳控制項個數,點擊“提交”按鈕後用於保存上傳的附件路徑,以便數據保存失敗時刪除附件。
下麵我們來看下前臺的html代碼。
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AttaUpload.ascx.cs" Inherits="WEB.webcontrols.AttaUpload" %> <script src="../js/AttaUpload.js" type="text/javascript"></script> <div id="tabEdit" runat="server"> <asp:Repeater ID="rpFileE" runat="server" OnItemCommand="rpFile_ItemCommand"> <ItemTemplate> <div> <asp:LinkButton ID="lbn_load" CommandArgument='<%#Eval("ID") %>' CommandName="load" runat="server" Style="line-height: 25px"><%# Eval("FileName").ToString() + Eval("FileType").ToString()%></asp:LinkButton>    <asp:LinkButton ID="lbtn_del" Style="color: Blue" CommandArgument='<%#Eval("ID") %>' CommandName="del" runat="server" OnClientClick='<%#"return DelMsg(\"「"+Eval("FileName").ToString() + Eval("FileType").ToString()+"」\")" %>'>刪除</asp:LinkButton> </div> </ItemTemplate> </asp:Repeater> <div id="atta" runat="server"> <asp:FileUpload ID="fufile" runat="server" onchange="if(this.value)JudgeFile(this.value,this);" /> <asp:ImageButton ID="imgbtn_add" runat="server" src="../images/add.gif" Style="margin-bottom: -2px;" /> </div> <asp:HiddenField ID="hffile" runat="server" Value="1" /> </div> <div id="tabView" runat="server" visible="false"> <asp:Repeater ID="rpFileV" runat="server" OnItemCommand="rpFile_ItemCommand"> <ItemTemplate> <div> <asp:LinkButton ID="lbn_load" CommandArgument='<%#Eval("ID") %>' CommandName="load" runat="server" Style="line-height: 25px"><%# Eval("FileName").ToString() + Eval("FileType").ToString()%></asp:LinkButton> </div> </ItemTemplate> </asp:Repeater> <asp:Literal ID="ltlfile" runat="server"></asp:Literal> </div>View Code
其中引用的AttaUpload.js文件,就是該控制項用到的所有JS代碼所在,裡面包含有動態創建上傳控制項,刪除附件提示,刪除動態創建的上傳控制項,判斷附件類型等等相關功能的JS編碼。
/**********動態添加上傳附件**********/ function AddAtta(id, hfid) { //var hfid = jQuery("#" + id).next().attr('id'); //document.getElementById(id).nextSibling.id;(IE10不相容) var d = document.createElement("div"); var f = document.createElement("input"); f.setAttribute("type", "file"); f.setAttribute("name", "upfile"); f.setAttribute("style", "margin-top:5px;"); f.onchange = function () { if (this.value) JudgeFile(this.value, this); } d.appendChild(f); //添加刪除按鈕 var im = document.createElement("img"); im.setAttribute("src", "../images/close.gif"); im.style.cssText = "margin-left:3px;margin-bottom: -2px;cursor:pointer"; im.onclick = function () { document.getElementById(hfid).value = $val(hfid) - 1; return DelFile(this, "DIV"); } d.appendChild(im); document.getElementById(id).appendChild(d); //添加計數 document.getElementById(hfid).value = parseInt($val(hfid)) + 1; return false; } /**********刪除**********/ function DelFile(f, name) { while (f.tagName != name) f = f.parentNode; f.parentNode.removeChild(f); return false; } /**********判斷文件類型和大小**********/ function JudgeFile(file, node) { var typelist = ["txt", "doc", "xls", "ppt", "docx", "xlsx", "pptx", "pdf", "jpeg", "jpg", "png", "bmp", "gif"]; if (file) { var match = 0; var suffix = file.split("."); var num = suffix.length - 1; var name = suffix[num].toLowerCase(); for (var i = 0; i < typelist.length; i++) { if (name == typelist[i]) { match = 1; break; } } if (match != 1) { alert("暫不支持上傳該類型的文件,請重新選擇!"); node.outerHTML = node.outerHTML; } } getFileSize(node); } //判斷文件大小 function getFileSize(obj) { var size = 0; if (navigator.userAgent.indexOf("MSIE") > 0) { try { var fso = new ActiveXObject('Scripting.FileSystemObject'); //獲取上傳文件的對象 var file = fso.GetFile(obj.value); size = file.Size; } catch (err) { size = 0; } } else { size = obj.files[0].size; } if ((size / 1048576) > 40) { alert("上傳文件大於40M,無法上傳!"); obj.outerHTML = obj.outerHTML; } } /**********刪除信息提示框**********/ function DelMsg(mess) { return confirm("系統提示:您確認刪除" + mess + "嗎?"); }View Code
現在我們來看下控制項的後臺編碼:
1、參數:
/// <summary> /// 項目ID /// </summary> public string ProID { get { if (ViewState["AttaProID"] == null) { return ""; } else { return (string)ViewState["AttaProID"]; } } set { ViewState["AttaProID"] = value; } } /// <summary> /// 控制項ID /// </summary> public string WucID { get { if (ViewState["AttaWucID"] == null) { return "AttaUp"; } else { return (string)ViewState["AttaWucID"]; } } set { ViewState["AttaWucID"] = value; } } /// <summary> /// 查看或編輯(0:編輯;1:查看) /// </summary> public string Flag { get { if (ViewState["AttaFlag"] == null) { return "0"; } else { return (string)ViewState["AttaFlag"]; } } set { ViewState["AttaFlag"] = value; } }View Code
2、頁面載入:
/// <summary> /// 載入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { imgbtn_add.Attributes.Add("onclick", "return AddAtta('" + WucID + "_atta','" + WucID + "_hffile')"); //頁面附件綁定 if (ProID != "") { //讀取現有數據 InitData(); } } }View Code
關於在後臺給“添加”按鈕綁定JS方法,是為了要把控制項的ID傳到前臺,否則“動態創建上傳控制項”和“保存累計個數”的方法就不能使用了。
而如果id="atta"的div不加上runat="server"的話,那任何頁面就只能使用一次了。
3、綁定數據:
/// <summary> /// 讀取數據 /// </summary> private void InitData() { PrjFileEntity model = new PrjFileEntity(); model.ProID = ProID; model.FileFlag = -2; DataView dv = PrjFileBLL.GetContact(model).DefaultView; if (Flag == "0") { // 編輯數據 rpFileE.DataSource = dv; rpFileE.DataBind(); } else { // 查看數據 rpFileV.DataSource = dv; rpFileV.DataBind(); tabEdit.Visible = false; tabView.Visible = true; if (dv == null || dv.Count <= 0) { ltlfile.Text = " "; } } }View Code
4、保存附件:
/// <summary> /// 保存附件 /// </summary> /// <param name="proid"></param> public PrjFileEntity Save(int start, string path, string ucid) { int one = Convert.ToInt32(hffile.Value); PrjFileEntity filemodel = CommonFunction.FileUpLoad(start, one + start, hffile, path, ucid, (int)CommonEnum.FileFlag.上傳); if (filemodel.ID == "-2") { CommonFunction.delfile(hffile.Value.ToString()); hffile.Value = "1"; ShowMessages(filemodel.FileName); return null; } else { return filemodel; } }View Code
/// <summary> /// 項目文檔上傳文件 /// </summary> /// <param name="start">起始值</param> /// <param name="end">終止值</param> /// <param name="hfcount">隱藏控制項</param> /// <param name="url">路徑(例:project/123)</param> /// <param name="ucid">用戶控制項ID(UserContronlID)</param> /// <param name="fileflag">附件標識(CommonEnum.FileFlag)</param> /// <returns></returns> public static PrjFileEntity FileUpLoad(int start, int end, HiddenField hfcount, string url, string ucid, int fileflag) { int upsize = 40000000; try { upsize = Convert.ToInt32(ConfigurationManager.AppSettings["upsize"].ToString()); } catch (Exception) { upsize = 40000000; } //清空隱藏控制項的值,用於存放路徑 if (hfcount != null) { hfcount.Value = ""; } //設置上傳路徑 string path = System.Web.HttpContext.Current.Server.MapPath("~/UpFile/" + url + "/"); //判斷上傳文件夾是否存在,若不存在,則創建 if (!Directory.Exists(path)) { //創建文件夾 Directory.CreateDirectory(path); } string attaname = ""; string attaurl = ""; string attatype = ""; PrjFileEntity accessinfo = null; HttpFileCollection files = HttpContext.Current.Request.Files; for (int i = start; i < end; i++) { HttpPostedFile postedFile = files[i]; if (postedFile.FileName != "") { if (postedFile.ContentLength < upsize) { string[] name = postedFile.FileName.ToString().Split('\\'); //獲取擴展名 string extname = System.IO.Path.GetExtension(postedFile.FileName); //獲取上傳文件的名稱 string oglname = name[name.Length - 1].ToString().Replace(extname, ""); //存儲上傳的文件名 attaname += oglname + ","; attatype += extname + ","; //為上傳的文件設置新的名稱,防止重名 string newname = System.DateTime.Now.ToString("yyyyMMddHHmmssffff") + i.ToString(); newname = newname + extname; //設置完整的文件上傳路徑 string filepath = path + newname; postedFile.SaveAs(filepath); if (hfcount != null) { hfcount.Value += filepath + "$"; } int j = filepath.IndexOf("UpFile"); string str = filepath.Substring(j - 1); attaurl += "~" + str + ","; } else { accessinfo = new PrjFileEntity(); accessinfo.ID = "-2"; accessinfo.FileName = "上傳失敗,上傳文件不能大於" + upsize / 1000000 + "M!"; return accessinfo; } } } attatype = attatype.TrimEnd(','); attaname = attaname.TrimEnd(','); attaurl = attaurl.TrimEnd(','); if (attaname != "" && attaurl != "" && attatype != "") { accessinfo = new PrjFileEntity(attatype, attaname, attaurl, ucid, fileflag); } else { accessinfo = new PrjFileEntity(); } return accessinfo; }View Code
5、刪除附件:
/// <summary> /// 刪除附件 /// </summary> public void Delete() { CommonFunction.delfile(hffile.Value.ToString()); hffile.Value = "1"; }View Code
6、附件下載及刪除:
/// <summary> /// 附件下載及刪除 /// </summary> /// <param name="source"></param> /// <param name="e"></param> protected void rpFile_ItemCommand(object source, RepeaterCommandEventArgs e) { string id = e.CommandArgument.ToString().Trim(); PrjFileEntity fileinfo = PrjFileBLL.GetUniqueObj(id); string path = fileinfo.FilePath; if (e.CommandName.ToString() == "del") { path = HttpContext.Current.Server.MapPath(path); bool istrue = PrjFileBLL.Delete(id); if (istrue) { //物理路徑的文件刪除 if (System.IO.File.Exists(path)) { System.IO.File.Delete(path); } ShowMessages("刪除成功"); //InitData(); //表單附件綁定 if (WorkTaskInsID != "") { FormData(); } //頁面附件綁定 else if (ProID != "") { //讀取現有數據 InitData(); } } else { ShowMessages("刪除失敗"); } } else { ShowScript("AttaView(\"" + id + "\",1)"); } }View Code
7、消息提醒:
/// <summary> /// 消息提醒 /// </summary> /// <param name="sMessage"></param> private void ShowMessages(string sMessage) { Page.ClientScript.RegisterStartupScript(this.GetType(), "Message", "<script>alert('系統提示:" + sMessage + "!');</script>"); return; } /// <summary> /// 運行純腳本 /// </summary> /// <param name="sMessage"></param> public void ShowScript(string script) { Page.ClientScript.RegisterStartupScript(GetType(), "", script, true); }View Code
8、獲取隱藏控制項的計數:
/// <summary> /// 獲取隱藏控制項的數值 /// </summary> /// <returns></returns> public int GetHiddenCount() { return Convert.ToInt32(hffile.Value); }View Code
此方法在頁面調用兩個或兩個以上此控制項的時候使用。
最後看下調用:
1、在webconfig中註冊:
<add src="~/webcontrols/AttaUpload.ascx" tagName="AttaUp" tagPrefix="wuc"/>
2、頁面前臺調用:
<tr> <th> 附件 </th> <td colspan="3"> <wuc:AttaUp ID="AttaUp" runat="server" /> </td> </tr>
3、頁面載入時傳遞參數:
//附件 AttaUp.ProID = CID; //查看時才傳,編輯時不需要 AttaUp.Flag = "1";
至於控制項的WucID參數,再沒有修改控制項ID的情況下不需要傳遞,如果你把控制項的ID重命名了,例如改為“FileUpControl”時,則一定要傳遞,否則會報錯!!
4、提交頁面時調用:
PrjFileEntity filemodel = AttaUp.Save(0, CommonFunction.GetProjectPath(hfproid.Value), "");
第一參數“0”,表示是從第一個上傳控制項開始查找附件;如果有兩個上傳控制項,那麼第一個控制項保存附件時,傳“0”;第二個則要用第一控制項的GetHiddenCount()方法,獲取第一個控制項的上傳控制項個數;如果有第三個控制項,那就要“累加”第一個控制項和第二個控制項的GetHiddenCount()方法的返回值。以此類推!!
註意:該方法只是返回了附件的實體類,多附件的每個屬性值都以逗號(,)隔開,詳情請仔細閱讀FileUpLoad()方法。