[系列文章]上传文件管理控件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>
posted @ 2008-05-28 03:25  柳城之城  阅读(2592)  评论(7编辑  收藏  举报