多附件上传控件

以前写过一篇《单页面多类型的多附件上传》的文章,但是在实际项目中,这样的并不多见,相比之下,多附件上传却经常用到。

而每次使用都要复制粘贴相关的代码,虽然不麻烦,但用起来却不太方便,一旦忘记某段代码没复制过来,页面就会报错。

于是,就想把现在用的这些代码,变成一个用户自定义控件,这样再次使用的时候就方便多了。

话不多说,先看下界面吧。

设计时

运行后

先介绍下控件界面,上下一共有两个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>&emsp;&emsp;&emsp;
                <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 = "&nbsp;";
                }
            }
        }
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()方法。

     如果你需要返回List<PrjFileEntity>,那么请自行修改FileUpLoad()方法。

5、页面数据保存失败时调用:

AttaUp.Delete();//删除上传的附件

  因为我是通过点击“提交”按钮,来保存表单数据。而保存失败时会刷新页面,导致附件控件被重置,那么在保存数据前被上传的附件,就无法看到。

  所以我需要删除之前上传的附件,让客户重新选择附件上传,虽然这样有点反人类,呵呵。如果你有好的解决办法,还请不吝赐教!

至此,整个多附件上传控件就介绍完毕了。

原文地址:https://www.cnblogs.com/lxc89/p/5580181.html