动态列的GridView嵌套解决方法整理

最近使用GridView做报表时遇到一个问题,在老大帮助下完成。现在记录一下。

项目需求类似如下的嵌套:

(例如一个借还系统,父级是借设备人的资料,子级是具体设备资料)

-------------------------

父编号   姓名   年龄

1         张三    20

      ----------------

      子编号   产品类型    产品名称

       1          路由器       凌凯    

      ----------------

2        李四      24

--------------------------

 

1.在一级数据的列数固定的情况下可直接使用如下嵌套:

基本思路是在行绑定事件中绑定嵌套的GridView2,这里如果GrideView2是动态列也可以,后台也能动态添加进去。

 

前台:

代码
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" 
            onrowdatabound
="GridView1_RowDataBound">
        
<Columns>
        
<asp:TemplateField HeaderText="编号">
        
<ItemTemplate><%#Eval("id"%></ItemTemplate>
        
</asp:TemplateField>
        
<asp:TemplateField HeaderText="姓名">
        
<ItemTemplate><%#Eval("name"%></ItemTemplate>
        
</asp:TemplateField>
        
<asp:TemplateField HeaderText="年龄" >
        
<ItemTemplate><%#Eval("age"%></ItemTemplate>
        
</asp:TemplateField>
        
        
<asp:TemplateField>        
        
<ItemTemplate>    
      <tr colspan="3">    
            
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="false">
            
<Columns>
            
<asp:TemplateField HeaderText="编号">
            
<ItemTemplate><%#Eval("id"%></ItemTemplate>
            
</asp:TemplateField>
            
            
<asp:TemplateField HeaderText="类型">
            
<ItemTemplate><%#Eval("type"%></ItemTemplate>
            
</asp:TemplateField>
            
            
<asp:TemplateField HeaderText="名称">
            
<ItemTemplate><%#Eval("name"%></ItemTemplate>
            
</asp:TemplateField> 
            
</Columns>
            
</asp:GridView>
      </tr>
        
</ItemTemplate>
        
</asp:TemplateField>                 
        
</Columns>
        
</asp:GridView>

 

 

后台:

代码
protected void Page_Load(object sender, EventArgs e)
    {
        DataTable dt 
= new DataTable();
        dt.Columns.Add(
"id");
        dt.Columns.Add(
"name");
        dt.Columns.Add(
"age");
        
for (int i = 0; i < 3;i++ )
        {
            dt.Rows.Add(i.ToString(),
"用户"+i,20+i);
        }
        DataSet ds 
= new DataSet();
        ds.Tables.Add(dt);
        
this.GridView1.DataSource = ds;
        
this.GridView1.DataBind();

    }
    
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        
if (e.Row.RowType == DataControlRowType.DataRow)
        {
            GridView gv 
= e.Row.FindControl("GridView2"as GridView;
            DataTable dt 
= new DataTable();
            dt.Columns.Add(
"id");
            dt.Columns.Add(
"name");
            dt.Columns.Add(
"type");
            
for (int i = 0; i < 3; i++)
            {
                dt.Rows.Add(i.ToString(), 
"产品" + i, "产品" + i);
            }
            DataSet ds 
= new DataSet();
            ds.Tables.Add(dt);
            gv.DataSource 
= ds;
            gv.DataBind();
        }
    }

 

 

2,一级数据的行中含有动态

 

开始考虑是动态的加列就可以了,我们在Page_Load事件中增加下面代码:

代码
    for (int i = 0; i < 2;i++ )//向模板列中插入几列
        {
            BoundField bf 
= new BoundField();
            bf.HeaderText 
= "测试"+i;
            bf.DataField 
= "name";
            
this.GridView1.Columns.Insert(1,bf);
        }

 

此时动态列增加上了,但是分页时在行绑定事件中已经找不到嵌套的GridView2了,原因我现在还不知道,请知道的朋友告知一下。
编号 测试1 测试0 姓名 年龄  
0 用户0 用户0 用户0 20
编号 类型 名称
0 产品0 产品0
1 产品1 产品1
2 产品2 产品2
1用户1用户1用户121

编号 类型 名称
0 产品0 产品0
1 产品1 产品1
2 产品2 产品2

 

于是,到这里就想到自己写一个模板类了,控制更好一些,在写的过程中老大给了帮助,模板如下

 

代码
#region MyTemplate
    
/// <summary>
    
///MyTemplate 的摘要说明
    
/// </summary>
    public class MyTemplate : ITemplate
    {
        
private DataControlRowType dataControlRowType;

        
private string dataField;
        
public string DataField
        {
            
get { return dataField; }
            
set { dataField = value; }
        }

        
private string columnName;
        
public string ColumnName
        {
            
get { return columnName; }
            
set { columnName = value; }
        }

        
private string controlID;
        
public string ControlID
        {
            
get { return controlID; }
            
set { controlID = value; }
        }

        
private bool isGrid;
        
public bool IsGrid
        {
            
get { return isGrid; }
            
set { isGrid = value; }
        }

        
public MyTemplate(string columnName)
        {
            dataControlRowType 
= DataControlRowType.Header;
            
this.columnName = columnName;
        }

        
public MyTemplate(string controlID, string dataField, bool isGrid)
        {
            dataControlRowType 
= DataControlRowType.DataRow;
            
this.dataField = dataField;
            
this.controlID = controlID;
            
this.isGrid = isGrid;
        }

        
#region ITemplate 成员
        JXSoft.TicketManage.BLL.TicketTypeBLL ticketTypeBLL 
= new JXSoft.TicketManage.BLL.TicketTypeBLL();
        
        
void ITemplate.InstantiateIn(Control container)
        {
            
switch (dataControlRowType)
            {
                
case DataControlRowType.Header:
                    Literal l 
= new Literal();
                    l.Text 
= ColumnName;
                    container.Controls.Add(l);
                    
break;
                
case DataControlRowType.DataRow:
                    
if (!isGrid)
                    {
                        Label lbl 
= new Label();
                        lbl.ID 
= ControlID;
                        lbl.DataBinding 
+= new EventHandler(lbl_DataBinding);
                        container.Controls.Add(lbl);
                    }
                    
else
                    {
                        Label lbl 
= new Label();
                        lbl.ID 
= ControlID;
                        lbl.DataBinding 
+= new EventHandler(lbl_DataBinding);
                        container.Controls.Add(lbl);

                        
#region 添加GridView 及内部绑定列
                        GridView gv 
= new GridView();
                        gv.ID 
= "GridView2";
                        gv.AutoGenerateColumns 
= false;

                        BoundField bf;

                        bf 
= new BoundField();
                        bf.HeaderText 
= "编号";
                        bf.DataField 
= "id";
                        gv.Columns.Add(bf);

                        bf 
= new BoundField();
                        bf.HeaderText 
= "类型";
                        bf.DataField 
= "type";
                        gv.Columns.Add(bf);

                        bf 
= new BoundField();
                        bf.HeaderText 
= "名称";
                        bf.DataField 
= "name";
                        gv.Columns.Add(bf);  
 
                        TableRow trow 
= new TableRow();
                        TableCell cell 
= new TableCell(); 
                        cell.ColumnSpan 
= 3;
                        cell.Controls.Add(gv);
                        trow.Cells.Add(cell);

                        container.Controls.Add(trow);
                        
#endregion
                    
                    }
                    
break;
                
default:
                    
break;
            }
        }

        
void lbl_DataBinding(object sender, EventArgs e)
        {
            Label lbl 
= sender as Label;
            GridViewRow gr 
= lbl.NamingContainer as GridViewRow;
            lbl.Text 
= DataBinder.Eval(gr.DataItem, DataField).ToString();
        }

        
#endregion
    }
    
#endregion

 

 也就是说我们可以在后台将所有的模板列动态的添加进GridView1

代码
        TemplateField tf;

        tf 
= new TemplateField();
        tf.HeaderTemplate 
= new MyTemplate("编号");
        tf.ItemTemplate 
= new MyTemplate("lblId""id"false);
        GridView1.Columns.Add(tf);

        tf 
= new TemplateField();
        tf.HeaderTemplate 
= new MyTemplate("姓名");
        tf.ItemTemplate 
= new MyTemplate("lblName""name"false);
        GridView1.Columns.Add(tf);

        tf 
= new TemplateField();
        tf.HeaderTemplate 
= new MyTemplate("年龄");
        tf.ItemTemplate 
= new MyTemplate("lblAge""age"false);
        GridView1.Columns.Add(tf);

        tf 
= new TemplateField();
        tf.HeaderTemplate 
= new MyTemplate("");
        tf.ItemTemplate 
= new MyTemplate("GridView1""age"true);
        GridView1.Columns.Add(tf);

 

接下来就可以在行绑定事件中找到GridView2并绑定数据了。分页也没问题。

当然也可以顺利导出。导出需要加以下代码:

 

代码
        protected void btnExport_Click(object sender, EventArgs e)
        {
            
this.GridView1.AllowPaging = false;
            BindDetailReportToGv(); 

            Response.Clear(); 
            Response.AddHeader(
"content-disposition""attachment;filename=DetailsLog.xls");
            Response.ContentType 
= "application/vnd.xls";
            System.IO.StringWriter sw 
= new System.IO.StringWriter();
            System.Web.UI.HtmlTextWriter htmlWrite 
= new HtmlTextWriter(sw);
            
this.GridView1.RenderControl(htmlWrite);
            Response.Write(sw.ToString());
            Response.End();
            
this.GridView1.AllowPaging = true;
        }

        
public override void VerifyRenderingInServerForm(Control control)
        {
            
// Confirms that an HtmlForm control is rendered for 
        }

 

 

其实解决这个问题应该还有更好的办法,关键在于2点:

第一个问题是如果一级数据中有动态列,那么分页时的行绑定事件内找不到行里的GridView2,

第二个问题是导出数据时由于采用colspan=“100%”,页面看上去是嵌套了,但是导出为excel后布局就会乱了。

您有更好的办法吗,欢迎交流。

 

 

posted @ 2010-04-14 11:23  翁玉礼  阅读(3252)  评论(1编辑  收藏  举报