代码改变世界

ASP.NET DEMO 17: 动态创建GridView绑定列/模板列

2008-05-25 23:39 by 晓风残月, ... 阅读, ... 评论, 收藏, 编辑
  • 可以发现运行时创建GridView模板列是很繁琐的事情,因此没有特殊需求,应该使用页面声明方式,动态解析构造Template这些繁琐易错的事情交由ASP.NET解析器完成。
  • 运行时动态任何服务器控件,必须确保每次请求/回发时,动态创建控件代码都能运行,典型错误是将这些放在一个Button_Click中,当其他PostBack的时候,这些控件将会丢失。
  • 代码技巧:匿名方法与 as 关键字的使用(C#中类型转换)
  • 很多朋友想通过动态创建列,来按需加载目标列,想法是好的,但鉴于ASP.NET原理特别是生命周期与ViewState的特殊性,这是易错又吃力不讨好的苦差事。
    个人建议是使用:
    • 假如DataSource是DataTable/DataView(或者DTO),使其包含只需要的Column,设置GridView.AutoGenerateColumns=true,由GridView内部在运行时自动反射创建列。
    • 以声明方式声明全部所需的Column,运行时调整GridView.Columns[index].Visible来控制列的可见性。
  • 代码下载
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%--http://topic.csdn.net/u/20080523/01/bab3a401-ab6d-4a9f-b946-aa04ea132442.html--%>
<%--ASP.NET 2.0中动态添加GridView 模板列的例子http://dotnet.aspx.cc/article/897cb049-ccff-4fe7-b990-df974493a0b1/read.aspx (孟老大)--%>
<script runat="server">
GridView grdStudent;
public enum StudentGridViewHeader
{
StudentNO,
Name,
Age,
Gender
}
public class StudentGridViewTemplate : ITemplate
{
private DataControlRowType rowType;
private DataControlRowState rowState;
private StudentGridViewHeader header;
public StudentGridViewTemplate(StudentGridViewHeader header, DataControlRowType rowType)
: this(header, rowType, DataControlRowState.Normal)
{
}
public StudentGridViewTemplate(StudentGridViewHeader header, DataControlRowType rowType, DataControlRowState rowState)
{
this.header = header;
this.rowType = rowType;
this.rowState = rowState;   // 未使用,保留备用
}
public void InstantiateIn(Control container)
{
switch (rowType)
{
case DataControlRowType.Header:
Literal ltlHeader = new Literal();
ltlHeader.Text = header.ToString();
container.Controls.Add(ltlHeader);
break;
case DataControlRowType.DataRow:
switch (header)
{
case StudentGridViewHeader.StudentNO:
HyperLink lnkStudentNO = new HyperLink();
lnkStudentNO.DataBinding += delegate(object sender, EventArgs e) // 匿名方法
{
object dataItem = ((sender as Control).NamingContainer as GridViewRow).DataItem;
lnkStudentNO.Text = (dataItem as DataRowView)["StudentNO"].ToString(); // 假如确定数据源是DataSet/DataTable/DataView 可使用强类型,避免反射,提升性能
lnkStudentNO.NavigateUrl = DataBinder.Eval(dataItem, "StudentNO", "studentdetail.aspx?sno={0}"); // 保持通用数据源,使用反射,以性能为代价
};
container.Controls.Add(lnkStudentNO);
break;
case StudentGridViewHeader.Name:
Literal ltlName = new Literal();
ltlName.DataBinding += delegate(object sender, EventArgs e)
{
object dataItem = ((sender as Control).NamingContainer as GridViewRow).DataItem;
ltlName.Text = DataBinder.Eval(dataItem, "LastName") + " " + DataBinder.Eval(dataItem, "FirstName");
};
container.Controls.Add(ltlName);
break;
case StudentGridViewHeader.Gender:
DropDownList ddlGender = new DropDownList();
ddlGender.Items.AddRange(new ListItem[] { new ListItem("Male", "M"), new ListItem("Female", "F") });
ddlGender.DataBound += delegate(object sender, EventArgs e)
{
object dataItem = ((sender as Control).NamingContainer as GridViewRow).DataItem;
ddlGender.SelectedValue = DataBinder.Eval(dataItem, "Gender").ToString(); // 设置正确的选中项
};
container.Controls.Add(ddlGender);
break;
default:
throw new InvalidOperationException("NotSupported StudentGridViewHeader: " + header.ToString());
}
break;
default:
throw new InvalidOperationException("NotSupported GridViewRowType: " + rowType.ToString());
}
}
}
void CreateStudentGridView()
{
//
grdStudent = new GridView();
grdStudent.AutoGenerateColumns = false;
grdStudent.RowDataBound += delegate(object sender, GridViewRowEventArgs e)
{
};
//
TemplateField tplField = new TemplateField();
tplField.ShowHeader = true;
tplField.HeaderTemplate = new StudentGridViewTemplate(StudentGridViewHeader.StudentNO, DataControlRowType.Header, DataControlRowState.Normal);
tplField.ItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.StudentNO, DataControlRowType.DataRow, DataControlRowState.Normal);
tplField.AlternatingItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.StudentNO, DataControlRowType.DataRow, DataControlRowState.Alternate);
grdStudent.Columns.Add(tplField);
//
tplField = new TemplateField();
tplField.ShowHeader = true;
tplField.HeaderTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Name, DataControlRowType.Header, DataControlRowState.Normal);
tplField.ItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Name, DataControlRowType.DataRow, DataControlRowState.Normal);
tplField.AlternatingItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Name, DataControlRowType.DataRow);
tplField.EditItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Name, DataControlRowType.DataRow, DataControlRowState.Edit);
grdStudent.Columns.Add(tplField);
//
BoundField bndField = new BoundField();
bndField.HeaderText = StudentGridViewHeader.Age.ToString();
bndField.DataField = StudentGridViewHeader.Age.ToString();
grdStudent.Columns.Add(bndField);
//
tplField = new TemplateField();
tplField.ShowHeader = true;
tplField.HeaderTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Gender, DataControlRowType.Header, DataControlRowState.Normal);
tplField.ItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Gender, DataControlRowType.DataRow, DataControlRowState.Normal);
tplField.AlternatingItemTemplate = new StudentGridViewTemplate(StudentGridViewHeader.Gender, DataControlRowType.DataRow, DataControlRowState.Alternate);
grdStudent.Columns.Add(tplField);

//
PlaceHolder1.Controls.Add(grdStudent);
}

void ShowStudentData()
{
if (grdStudent == null) throw new InvalidOperationException("The StudentGridView has not been created yet.");
DataTable dt = CreateSampleData();

grdStudent.DataSource = dt;
grdStudent.DataBind();
}

#region sample data

static DataTable CreateSampleEmptyDataTable()
{
DataTable tbl = new DataTable("Student");

tbl.Columns.Add("StudentNO", typeof(string));
tbl.Columns.Add("FirstName", typeof(string));
tbl.Columns.Add("LastName", typeof(string));
tbl.Columns.Add("Age", typeof(int));
tbl.Columns.Add("Gender", typeof(string));

return tbl;
}

static DataTable CreateSampleData()
{
DataTable tbl = CreateSampleEmptyDataTable();

tbl.Rows.Add("20021342", "Jack", "Wu", 25, "M");
tbl.Rows.Add("20025341", "Jue", "You", 23, "F");
tbl.Rows.Add("20022254", "Viky", "Huang", 24, "F");
tbl.Rows.Add("20022231", "Leo", "Wong", 24, "M");

return tbl;
}

#endregion

protected void Page_Init(object sender, EventArgs e)
{
// 确保每次回发都能动态创建GridView
CreateStudentGridView();
}

protected void Page_Load(object sender, EventArgs e)
{
// 回发不需要重新绑定数据,从ViewState填充数据
if (!IsPostBack)
{
ShowStudentData();
}
}

protected void Button1_Click(object sender, EventArgs e)
{

}
</script> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>DEMO17_GridViewDynamicalCreateOnFly</title> </head> <body> <form id="form1" runat="server"> <div> <h3> 在运行时动态创建GridView各种绑定列</h3> <ul> <li>可以发现运行时创建GridView模板列是很繁琐的事情,因此没有特殊需求,应该使用页面声明方式,动态解析构造Template这些繁琐易错的事情交由ASP.NET解析器完成。
</li> <li>运行时动态任何服务器控件,必须确保每次请求/回发时,动态创建控件代码都能运行,典型错误是将这些放在一个Button_Click中,当其他PostBack的时候,这些控件将会丢失。
</li> <li>代码技巧:匿名方法与as 关键字的使用(C#中类型转换)</li> <li>很多朋友想通过动态创建列,来按需加载目标列,想法是好的,但鉴于ASP.NET原理特别是生命周期与ViewState的特殊性,这是易错又吃力不讨好的苦差事。
<br> 个人建议是使用:</li> <ul> <li>假如DataSource是DataTable/DataView(或者DTO),使其包含只需要的Column,设置GridView.AutoGenerateColumns=true,由GridView内部在运行时自动反射创建列。
</li> <li>以声明方式声明全部所需的Column,运行时调整GridView.Columns[index].Visible来控制列的可见性。</li> </ul> </ul> <br /> <input id="Button2" type="button" value="Redirect" onclick="location.href=location.href;" /> <asp:Button ID="Button1" runat="server" Text="PostBack" OnClick="Button1_Click" /> <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder> </div> </form> </body> </html>