zoukankan      html  css  js  c++  java
  • [系列文章]上传文件管理控件v3

    上传文件管理控件v3:

    一、引言
    v2完成了将数据绑定在dataGrid上的任务,但是dataGrid毕竟是asp.net 1.x的工具,在asp.net 2.0里面,使用是gridveiw。接下来的问题就是将datagrid上的程序移植到gridview上面。
    二、更换控件
    最开始的时候,我觉得这两种东西本质上来讲都是一样的,差别应该只在名称上。当然,这理论我是不怎么自信的,我自学计算机技术这么多年,“理想”在“现实”面前遇到的问题不计其数,我只能“冒蒙”(东北方言)来试一试了。
    还好,只是在指定数据源上有所不同。

    dataGrid2.DataSource = new DataView(FileList);
    dataGrid2.DataBind();

    GridView1.DataSource = FileList;// new GridView(FileList);
    GridView1.DataBind();

    做到这里,大概是两天前22日的时候,所以当时太具体的情况记不清了。一开始的时候,只是把绑定的对象换了一下,然后vs编译未通过,改了一下就过去了。
    这部分没有什么特别之处,所以就不罗列代码了。
    三、整理代码:添加Band()方法
    载入页面的时候需要获取目录的内容并且将数据绑定到GridView上,删除之后也需要重新获取和绑定,所以要把获取目录和绑定的代码封装起来。所以,我把代码整理了一下,封装到了Band()方法。

    四、转换CheckBoxField控件为模板
    接下来的问题是,如果直接是将bool数据绑定到CheckBoxField控件,那么在进入编辑状态时,就是禁用状态,无法做到根据控件删除文件。无奈之下,只好转换成模板,结果就是CheckBoxField变成了CheckBox!最初我是直接复制网上的一代码,马上复选框就可以勾选了。然后,我尝试自己输入代码,结果调试的时候出现了错误。仔细一看,原来是单引号的问题。
    复制的代码来源:
    <asp:CheckBox ID="checkbox1" runat="server" ToolTip=' <%#Eval("id") %>'>
                  </asp:CheckBox>
    我自己转换的模板再加上手工输入的代码
    <asp:CheckBox ID="CheckBox1" runat="server" ToolTip='<%#Eval("文件名") %>'/>
    出错的地方:
    <asp:CheckBox ID="CheckBox1" runat="server" ToolTip=“<%#Eval("文件名") %>”/>
    然后,我又做了一个试验,先给CheckBoxField绑定数据,再将它转换为模板。在设计视图下,这人checkbox仍然是禁用的。可是我不死心,我觉得,不管怎么着,GridView总得给我一个能选的复选框吧?(呵呵,前面已经做出来了,所以我有信心。)进入源视图,看到的是:
            <asp:TemplateField HeaderText="选二" SortExpression="文件名">
                <EditItemTemplate>
                    <asp:CheckBox ID="CheckBox2" runat="server" Checked='<%# Bind("选择") %>' />
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:CheckBox ID="CheckBox2" runat="server" Checked='<%# Bind("选择") %>' Enabled="False" />
                </ItemTemplate>
            </asp:TemplateField>
    那么就是在这里了:Enabled="False",在HTML中,input标记有一个Disabled属性,而这里看到了Enabled(Disabled和Enabled是反义词),我觉得有门,可以试一试。在代码里修改一下Enabled="True",运行一下,看到的结果是成功了!
    然后我再回来看一遍代码:Eval和Band是怎么回事?这好像是一个很基础的问题,可是时间长了,我都忘记辨析它们的地方是哪里了,还好,MSDN上说得很清楚。

    五、用哪种方式删除

    其实写到这里的时候,v4的框架已经出来,本来打算v2和v3只是简略的写一下,做一个简略的过渡就行了,但是在查找资料的过程中,看到数种结合CheckBox删除的例子。于是忍不住,尝试一下,所以,这一系列文章的写作时间跨度有点长,这个V3本身的也就罗嗦了。
    删除的方式,主要有三种:
    第一种:添加按钮,在按钮的事件中判断复选框是否已经勾选,再根据复选框的属性删除。这是我首先测试并且成功的一种方法。后面我会介绍这个过程。
    第二种:也需要添加按钮,在按钮的事件中判断复选框,不同的时,第二种方法需要从DataKey获取值。
    第三种:增加删除列,单行删除。因为这个GridView使用的原始数据是文件对象数组,不是数据库,不能执行Sql的删除语句,所以在v3里是不能实现的。所以,才逼我出了v4,在v4里将会结合强大ObjcetDataSource,将数组模拟成数据库,让GridView能使用智能任务面板上的”删除“功能。使数组数据源看起更像数据库一些。
    ObjectDateSource,还有一种方式实现删除的,那就是CommandField控件。到底哪一种,在v4里面见分晓。

    六、使用CheckBox的属性获取值
    给CheckBox添加ToolTip属性后,浏览器看到的代码是:
    <span title="不能停下的节奏-月亮.mp3"><input id="ListUpload_v3_1_GridView1_ctl07_CheckBox1" type="checkbox" name="ListUpload_v3_1$GridView1$ctl07$CheckBox1" /></span>
    也就是说ToolTip属性在浏览器那里被转换成了title。这个是我在这个方案测试通过之后才发现的。目前我对Asp.net了解的实在是太浅了,所以我不禁怀疑,<span>标记也能传递值?可是我毕竟测试通过了呀!
    1、添加按钮和按钮的事件。按钮的ID是DelFileBt,事件是:DelFileBt_Click
    2、添加用来显示调试信息的lable,ID是ResultMsg2。(先前添加了一个TextBox,ID是ResultMsg1但是测试的时候,没有结果所以这个顺序排到2)
    3、处理DelFileBt_Click事件
        protected void DelFileBt_Click(object sender, EventArgs e)
        {
           
            if (IsPostBack)//这个东西搞不懂什么时候用,什么时候不用。
            {
                ResultMsg2.Text = "";//一开始没加这个,以前选中的项目就会反复出现
               
                for (int i = 0; i < GridView1.Rows.Count; i++)
                {
                    CheckBox cbx = GridView1.Rows[i].FindControl("CheckBox1") as CheckBox;
                    if (cbx.Checked)
                    {
                        ResultMsg2.Text += "<br/> i:" + i + " " + cbx.ToolTip;//调试信息:显示被选中的文件
          DelFile(cbx.ToolTip);//执行删除
                    }

                }
            }
        }
     
    七、从DataKey获取值
    这个方法最初的思想是希望使用其它数据列的值,但是在实际调试的过程中发现,使用Cells获取的是单元格对象,而不是我想象中的Fields。这里费了很大的力气,也让我再次体会,asp.net很多地方不能像asp那么简单直接。
    最后是翻书加上看MSDN,采用了的DataKey对象。

    1、添加按钮和按钮的事件。按钮的ID是DelFileBt2,事件是:DelFileBt2_Click
    2、添加用来显示调试信息的lable,ID是ResultMsg3。
    3、为GridView添加DataKeyNames,我这个控件,在删除的时候,只有文件名是有用的,所以只需要文件名一项即可。实际上经过测试,可以使用多项。
    多项的时候,是这个样子的:DataKeyNames="文件名,上传日期"
    4、处理DelFileBt2_Click事件
        protected void DelFileBt2_Click(object sender, EventArgs e)
        {
            ResultMsg3.Text = "";
            for (int i = 0; i < GridView1.Rows.Count; i++)
            {
                CheckBox cbx = GridView1.Rows[i].FindControl("CheckBox1") as CheckBox;
                if (cbx.Checked)
                {
                    GridView1.SelectedIndex = i;//SelectedIndex是个可取写的索引,可以通过它来设置哪一行被选中,再获取该行的DataKey

                    ResultMsg3.Text += "<br/> i:" + i; // +" " + GridView1.Rows[i].Cells[1].ID + " :" + GridView1.Rows[i].DataItem;//.DataKeys[0].Value;// GridView1.Rows[i].FindControl("文件名").Text;
                                                       //经过测试,上面注释这几个都是失败的,它们返回的都是值。
                    //DataKeys[0].Value开始的时候也是返回空值,原因是那时没有给GridView指定DataKeyNames
                   
                    ResultMsg3.Text += GridView1.SelectedDataKey.Value;//默认指向一行中一系列DataKey中的第一个,
                                                                       //SelectedDataKey.Value相当于SelectedDataKey.Values[0]
                   
                    ResultMsg3.Text += " DateKey.Values:" + GridView1.SelectedDataKey.Values[1];//可以获取任意某个SelectDatakey的值

                    ResultMsg3.Text += " @@@" + GridView1.DataKeys[i].Value;//这个是最简洁的用法,有它根本不必使用选中行,“GridView1.SelectedIndex”这上下两行,都用不上,最终我决定用它了。
                    DelFile(GridView1.DataKeys[i].Value);//执行删除
                   
                   
                }
                GridView1.SelectedIndex = -1;//取消选中行,如果没有这个,就会在页面上显示出最后一行已经是选中的状态。
            }
        }


    八、另一种循环和另一种获取值的办法
    在查找资料的时候,看到百度知道的另一种循环方式。它循环的是DataGrid对象中包含的DataGridItem集合。
    查看MSDN,GridView对象没有这样的Item集合,却找到GridViewRow集合,凭个人经验来看,这两个似乎是差不多的。
    在写代码的时候,忽然发现,其实这和前面循环Rows,是一样的,那么还要不要继续呢?我一直不死心,一直希望能够找到直接获取列值的方法。于是我便做了下去。
    要查看DataGridItem类的时候(MSDN),看到MSDN上用DataBoundLiteralControl获取列上面包含的控件,最后终于用这个办法获取到了列的值。
    今天有一个项目(asp)追得比较紧,所以具体的我就不多说了,下面是代码(我这边加到了DelFileBt2_Click里面):
            /*
             * 我前面用的是循环GridView1.Rows集合
             * 下面测试一下在网上看到的另外一种循环
             * 网上代码采用的是asp.net 1.x 的DataGrid对象和DataGridItem对象
             * 现在我用的是GridView对象和GridViewRow对象
             *
             */
            ResultMsg3.Text += "<hr/>下面开始测试另一种循环:<br/>";
            foreach (GridViewRow r in GridView1.Rows)
            {
                //MSDN有一种用法selectRow.Cells[2].Controls[0];,我也许可以试一下。

               
                //
                //经过测试,下面三种用法均无法获得值
                //
                ResultMsg3.Text += "<br/>DataItem:" + r.DataItem;
                ResultMsg3.Text += "  r.Cells[5].Text:" + r.Cells[5].Text;
                ResultMsg3.Text += "  r.Cells[1].Text:" + r.Cells[1].Text;


                /*
                 * 目前找到的唯一的一种能直接获取列内值的用法
                 * 但是要求采用下面的方法
                 *
                 * <asp:TemplateField HeaderText="测试列" Visible="False">
                 *      <ItemTemplate>
                 *           <%#Eval("文件名")%>
                 *      </ItemTemplate>
                 * </asp:TemplateField>
                 * 通过观察发现,浏览器显示的时候,直接在<td></td>里面放置文本。是否可以扩展Eval()实际更多功能,暂时没有研究。
                 * 如果数据列的表现形式不符台前台显示的要求,比如说需要制作链接功能。
                 * 可以像上面那样,通过设置Visible="False",在前台不显示这一列。
                 *
                 *
                 */
                DataBoundLiteralControl filename = (DataBoundLiteralControl)r.Cells[5].Controls[0];
                ResultMsg3.Text += "  filename.Tex:" + filename.Text;

            }

    ------------------下面是有关DataBoundLiteralControl 类 的资料(MSDN):
    DataBoundLiteralControl 类
    保留数据绑定表达式和静态文本。无法继承此类。

    DataBoundLiteralControl firstNameLiteral = (DataBoundLiteralControl)selectRow.Cells[2].Controls[0];
    String firstName = firstNameLiteral.Text;
    -------------------资料结束


    九、删除文件DelFile

        protected bool DelFile(string strFilename)
        {
           
            string filePath;//获取文件路径
            if (strDir.EndsWith("/"))//查看路径是不是以/结尾的
            {
               filePath = Server.MapPath(strDir + strFilename);
            }
            else
            {
               
             filePath= Server.MapPath(strDir + "/" + strFilename);  
            }
            Response.Write(filePath);
            FileInfo oFile = new FileInfo(filePath);

            if (oFile.Exists)//判断文件是否存在
            {
                oFile.Delete();
                Band();//重新绑定,要不然被删除的文件仍然会显示。
                return true;
            }
            else
            {
                Response.Write("对不起您操作的文件" + strFilename + "不存在。");
                return false;
            }
           
        }

    十、v3后记
    没想到后在v3这里使用这么长的时间。当然付出就会有收获,所以从v3这里收获也不少。
    现在想想v3遇到的这么多问题,我稍微有点担心,v4的删除会顺利吗?

    ::::::::::::::::::::::::::
    错误和调试心得:
    ①CheckBoxField,只能绑定Bool型的数据列,它只用来表示数据列中的Bool型的结果。如果绑定string int类型的数据就会出错。
    在默认的显示状态下是禁用的,只有编辑列的时候能勾选或者取消勾选,也就是说,平常用处不大。
    ②在asp.net服务器控件绑定的时候,属性里的格式是xxxx='<%#  Eval("ssss") %>' 。注意,外面用的单引号,否则会出错。在vs2005的代码状态下看到的是单引号,IIS传送给客户端浏览器却是双引号。
    ③查看MSDN,得知Eval 用来绑定只读的数据,Band则是支持读写的。下面是MSDN原话:Eval 方法是静态(只读)方法,该方法采用数据字段的值作为参数并将其作为字符串返回。Bind 方法支持读/写功能,可以检索数据绑定控件的值并将任何更改提交回数据库。
    也就是在“ItemTemplate”里用哪种都行,在“EditItemTemplate”里只能用Band。

    <%@ Control Language="C#" ClassName="ListUpload_v3" %>
    <%@ Import Namespace="System.IO" %>
    <%@ Import namespace="System.Data" %>

    <script runat="server">
        
    /**************************************************************** 
         **上传文件管理控件
         **文件名:ListUpload_v3.ascx  
         **Copyrigth(c) 2008-2010   *************** 柳城别日 xpnew.cnblogs.com
         **文件编号:
         **创建人:柳城别日
         **日期:2008年5月22日
         **修改人:柳城别日
         **日期:2008年5月24日
         * 描述:用来管理上传文件,支持列表、删除
         *
    */


        
    //

        
    /* class ListUpload2
         {
         }
         * 
         *
         * 
    */

        
    // 类内部初始化
        private string _strDir = @"~/Upload/";
        
        
        
    public string strDir//通过这个属性,可以设置控件所要管理的目录
        {
            
    get
            
    {
                
    return _strDir;
            }

            
    set
            
    {
                _strDir 
    = value;
            }

        }


        
    protected void Page_Load(object sender, EventArgs e)
        
    {
            
    if (!Page.IsPostBack)
            
    {
                
    //绑定

                Band();
            }

        }

        
    public void Band()
        
    {
            DataTable FileList 
    = new DataTable();
            
    //FileList为声明一个表

            DataRow FileItem;
            
    //表示Table中行的数据


            FileList.Columns.Add(
    new DataColumn("选择"typeof(bool)));
            FileList.Columns.Add(
    new DataColumn("文件名"typeof(string)));
            FileList.Columns.Add(
    new DataColumn("大小(字节)"typeof(Int32)));
            FileList.Columns.Add(
    new DataColumn("上传日期"typeof(DateTime)));
            
    //Columns为取值该表列的集合,
            
    //Add.为该表添加到列的集合 DataColumn为列框架
            
    //前面是列头的标题,后面表示该列的数据类型----这是别人的注释
            
    //我认为前面不单单是标题那么简单,在v4里后详细地说明


            
    string dirPath = Server.MapPath(strDir);
            DirectoryInfo Dir 
    = new DirectoryInfo(dirPath);
            FileInfo[] arrFiles 
    = Dir.GetFiles();

            
    foreach (FileInfo f in arrFiles)
            
    {
                FileItem 
    = FileList.NewRow();
                
    //创建与该表具有相同框架新的数据行
                FileItem[0= false;
                FileItem[
    1= f.Name;
                FileItem[
    2= f.Length;
                FileItem[
    3= f.LastWriteTime;
                
    //为数据行添加数值

                FileList.Rows.Add(FileItem);
                
    //把获得数值的指定的行加到该表的集合

            }


            GridView1.DataSource 
    = FileList;// new GridView(FileList);
            GridView1.DataBind();

        }






        
    protected void DelFileBt_Click(object sender, EventArgs e)
        
    {
            
            
    if (IsPostBack)
            
    {
                ResultMsg2.Text 
    = "";
                
                
    for (int i = 0; i < GridView1.Rows.Count; i++)
                
    {
                    CheckBox cbx 
    = GridView1.Rows[i].FindControl("CheckBox1"as CheckBox;
                    
    if (cbx.Checked)
                    
    {
                        ResultMsg2.Text 
    += "<br/> i:" + i + " " + cbx.ToolTip;
                    }


                }

            }

        }


        
    protected void DelFileBt2_Click(object sender, EventArgs e)
        
    {
            ResultMsg3.Text 
    = "";
            
    for (int i = 0; i < GridView1.Rows.Count; i++)
            
    {
                CheckBox cbx 
    = GridView1.Rows[i].FindControl("CheckBox1"as CheckBox;
                
    if (cbx.Checked)
                
    {
                    GridView1.SelectedIndex 
    = i;//SelectedIndex是个可取写的索引,可以通过它来设置哪一行被选中,再获取该行的DataKey

                    ResultMsg3.Text 
    += "<br/> i:" + i; // +" " + GridView1.Rows[i].Cells[1].ID + " :" + GridView1.Rows[i].DataItem;//.DataKeys[0].Value;// GridView1.Rows[i].FindControl("文件名").Text;
                                                       
    //经过测试,上面注释这几个都是失败的,它们返回的都是值。
                    
    //DataKeys[0].Value开始的时候也是返回空值,原因是那时没有给GridView指定DataKeyNames
                    
                    ResultMsg3.Text 
    += GridView1.SelectedDataKey.Value;//默认指向一行中一系列DataKey中的第一个,
                                                                       
    //SelectedDataKey.Value相当于SelectedDataKey.Values[0]
                    
                    ResultMsg3.Text 
    += " DateKey.Values:" + GridView1.SelectedDataKey.Values[1];//可以获取任意某个SelectDatakey的值

                    ResultMsg3.Text 
    += " @@@" + GridView1.DataKeys[i].Value;
                    DelFile(GridView1.DataKeys[i].Value.ToString());
    //执行删除                
                    
                    
                }

                GridView1.SelectedIndex 
    = -1;
            }


            
    /*
             * 我前面用的是循环GridView1.Rows集合
             * 下面测试一下在网上看到的另外一种循环
             * 网上代码采用的是asp.net 1.x 的DataGrid对象和DataGridItem对象
             * 现在我用的是GridView对象和GridViewRow对象
             *
             
    */

            ResultMsg3.Text 
    += "<hr/>下面开始测试另一种循环:<br/>";
            
    foreach (GridViewRow r in GridView1.Rows)
            
    {
                
    //MSDN有一种用法selectRow.Cells[2].Controls[0];,我也许可以试一下。

                
                
    //
                
    //经过测试,下面三种用法均无法获得值
                
    //
                ResultMsg3.Text += "<br/>DataItem:" + r.DataItem;
                ResultMsg3.Text 
    += "  r.Cells[5].Text:" + r.Cells[5].Text;
                ResultMsg3.Text 
    += "  r.Cells[1].Text:" + r.Cells[1].Text;


                
    /*
                 * 目前找到的唯一的一种能直接获取列内值的用法
                 * 但是要求采用下面的方法
                 * 
                 * <asp:TemplateField HeaderText="测试列" Visible="False">
                 *      <ItemTemplate>
                 *           <%#Eval("文件名")%>
                 *      </ItemTemplate>
                 * </asp:TemplateField>
                 * 通过观察发现,浏览器显示的时候,直接在<td></td>里面放置文本。是否可以扩展Eval()实际更多功能,暂时没有研究。
                 * 如果数据列的表现形式不符台前台显示的要求,比如说需要制作链接功能。
                 * 可以像上面那样,通过设置Visible="False",在前台不显示这一列。
                 * 
                 * 
                 
    */

                DataBoundLiteralControl filename 
    = (DataBoundLiteralControl)r.Cells[5].Controls[0];
                ResultMsg3.Text 
    += "  filename.Tex:" + filename.Text;

            }

        }


        
    protected bool DelFile(string strFilename)
        
    {
            
            
    string filePath;//获取文件路径
            if (strDir.EndsWith("/"))//查看路径是不是以/结尾的
            {
               filePath 
    = Server.MapPath(strDir + strFilename);
            }

            
    else
            
    {
                
             filePath
    = Server.MapPath(strDir + "/" + strFilename);   
            }

            Response.Write(filePath);
            FileInfo oFile 
    = new FileInfo(filePath);

            
    if (oFile.Exists)//判断文件是否存在
            {
                oFile.Delete();
                Band();
    //重新绑定,要不然被删除的文件仍然会显示。
                return true;
            }

            
    else
            
    {
                Response.Write(
    "对不起您操作的文件" + strFilename + "不存在。");
                
    return false;
            }

            
        }



    </script>

    &nbsp;<asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333"
        GridLines
    ="None" AutoGenerateColumns="False" DataKeyNames="文件名,上传日期">
        
    <FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
        
    <Columns>
            
    <asp:TemplateField HeaderText="">
                
    <EditItemTemplate>
                    
    <asp:CheckBox ID="CheckBox1" runat="server" ToolTip='<%#Eval("文件名") %>'/>
                
    </EditItemTemplate>
                
    <ItemTemplate>
                    
    <asp:CheckBox ID="CheckBox1" runat="server" ToolTip='<%#Eval("文件名") %>'/>
                
    </ItemTemplate>
            
    </asp:TemplateField>
            
    <asp:HyperLinkField DataNavigateUrlFormatString="upload/{0}" DataTextField="文件名" DataNavigateUrlFields="文件名" NavigateUrl="upload/" Target="_blank" />
            
    <asp:BoundField DataField="大小(字节)" />
            
    <asp:BoundField DataField="上传日期" />
            
    <asp:TemplateField HeaderText="选二" SortExpression="文件名">
                
    <EditItemTemplate>
                    
    <asp:CheckBox ID="CheckBox2" runat="server" Checked='<%# Bind("选择") %>' />
                
    </EditItemTemplate>
                
    <ItemTemplate>
                    
    <asp:CheckBox ID="CheckBox2" runat="server" Checked='<%# Bind("选择") %>' Enabled="True" />
                
    </ItemTemplate>
            
    </asp:TemplateField>
            
    <asp:TemplateField HeaderText="测试列" Visible="False">
                
    <ItemTemplate>
                    
    <%#Eval("文件名")%>
                
    </ItemTemplate>
            
    </asp:TemplateField>

        
    </Columns>
        
    <RowStyle BackColor="#E3EAEB" />
        
    <EditRowStyle BackColor="#7C6F57" />
        
    <SelectedRowStyle BackColor="#C5BBAF" Font-Bold="True" ForeColor="#333333" />
        
    <PagerStyle BackColor="#666666" ForeColor="White" HorizontalAlign="Center" />
        
    <HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />
        
    <AlternatingRowStyle BackColor="White" />
    </asp:GridView>
    <br />
    <asp:Button ID="DelFileBt" runat="server" OnClick="DelFileBt_Click" Text="删除" />&nbsp;&nbsp;
    <asp:Label ID="ResultMsg2" runat="server" Text="Label"></asp:Label>
    <br />
    <asp:Button ID="DelFileBt2" runat="server" OnClick="DelFileBt2_Click" Text="删除" />
    <asp:Label ID="ResultMsg3" runat="server" Text="Label"></asp:Label>
  • 相关阅读:
    linux ioctl
    pkg-config用法和gcc cflags
    boost noncopyable类
    google protobuf使用2
    跨平台编译CMake使用
    Linux epoll
    docker安装
    python 脚本转成exe可执行程序
    shell相关知识
    tcpdump使用
  • 原文地址:https://www.cnblogs.com/xpnew/p/1208816.html
Copyright © 2011-2022 走看看