GridView 一体化






4.89/5 (73投票s)
提供了有关使用 GridView 的清晰思路。
引言
我看到很多初学者在 GridView
上遇到困难,并且不起作用。为了在一定程度上解决这个问题,我创建了一个包含 GridView
大部分事件和属性的应用程序。这可能有助于清晰地了解如何使用 GridView
。该应用程序还包含一些 JavaScript 代码片段和样式表,可用于为 GridView
添加一些值。希望本文简单易懂且足够。
什么是 GridView?
DataGrid
或 GridView
控件以表格形式显示数据,并且还支持在网格本身内选择、排序、分页和编辑数据。DataGrid
或 GridView
为数据源中的每个字段生成一个 BoundColumn
(AutoGenerateColumns=true
)。通过直接将数据源分配给 GridView
,数据可以以其在数据源中出现的顺序渲染在单独的列中。默认情况下,字段名出现在网格的列标题中,值以文本标签的形式渲染。将应用默认格式到非字符串值,并且可以更改。
GridView 字段
列名 | 描述 |
BoundColumn |
用于控制列的顺序和渲染。 |
HyperLinkColumn |
以超链接控件的形式呈现绑定的数据 |
ButtonColumn |
将用户命令从行内冒泡到网格事件处理程序 |
TemplateColumn |
控制在列中渲染哪些控件 |
CommandField |
响应 DataGrid 控件的 EditItemIndex 属性的变化,显示编辑、更新和取消链接。 |
BoundColumn
通过在网格的 Columns
集合中显式创建 BoundColumn
,可以控制每一列的顺序和渲染。在 BoundField
属性中,当给出 DataField
和 SortExpression
时,可以轻松地进行排序和渲染数据。
HyperLinkColumn
HyperLinkColumn
以 HyperLink
控件的形式呈现绑定的数据。这通常用于通过直接在 NavigationUrl
中分配页面 URL 或从数据库渲染来从网格中的项导航到另一页上的详细信息视图。
TemplateColumn
使用 TemplateColumn
,可以控制在列中渲染的控件以及绑定到这些控件的数据字段。通过使用 TemplateColumn
,可以插入任何类型的数据控件。
通过单击“编辑模板”选项,可以打开模板字段,在那里我们可以看到可以添加的控件,如 Label
、CheckBox
,甚至 GridView
。
CommandField
EditCommandColumn
是一种特殊的列类型,它支持在网格的某一行中就地编辑数据。EditCommandColumn
与网格的另一个属性交互:EditItemIndex
。默认情况下,EditItemIndex
的值为 -1,表示网格中的任何行(项)都未被编辑。如果 EditItemIndex
为 -1,则在网格中每一行的 EditCommandColumn
中都会显示一个“编辑”按钮。
当单击“编辑”按钮时,会触发网格的 EditCommand
事件。由程序员在代码中处理此事件。典型的逻辑是将 EditItemIndex
设置为选定的行,然后将数据重新绑定到网格。
当 EditItemIndex
设置为特定行时,EditCommandColumn
将为该行显示“更新”和“取消”按钮(对于其他行仍显示“编辑”)。这些按钮分别触发 UpdateCommand
和 CancelCommand
事件。
不同类型的事件
名称 | 描述 |
DataBinding |
在服务器控件绑定到数据源时发生。(继承自 Control 。) |
DataBound |
在服务器控件绑定到数据源之后发生。(继承自 BaseDataBoundControl 。) |
Disposed |
在服务器控件从内存中释放时发生,这是 ASP.NET 页面请求时服务器控件生命周期的最后阶段。(继承自 Control 。) |
Init |
在服务器控件初始化时发生,这是其生命周期的第一步。(继承自 Control 。) |
Load (加载) |
在服务器控件加载到 Page 对象时发生。(继承自 Control 。) |
PageIndexChanged |
当单击分页按钮之一时发生,但在 GridView 控件处理分页操作之后。 |
PageIndexChanging |
当单击分页按钮之一时发生,但在 GridView 控件处理分页操作之前。 |
PreRender |
在 Control 对象加载后但在渲染之前发生。(继承自 Control 。) |
RowCancelingEdit |
当处于编辑模式的行的 Cancel 按钮被单击时发生,但在行退出编辑模式之前。 |
RowCommand |
在 GridView 控件中的按钮被单击时发生。 |
RowCreated |
在 GridView 控件中创建行时发生。 |
RowDataBound |
在 GridView 控件中将数据行绑定到数据时发生。 |
RowDeleted |
在单击行的 Delete 按钮后发生,但在 GridView 控件删除行之后。 |
RowDeleting |
在单击行的 Delete 按钮时发生,但在 GridView 控件删除行之前。 |
RowEditing |
在单击行的 Edit 按钮时发生,但在 GridView 控件进入编辑模式之前。 |
RowUpdated |
在单击行的 Update 按钮后发生,但在 GridView 控件更新行之后。 |
RowUpdating |
在单击行的 Update 按钮时发生,但在 GridView 控件更新行之前。 |
SelectedIndexChanged |
在单击行的 Select 按钮后发生,但在 GridView 控件处理 Select 操作之后。 |
SelectedIndexChanging |
在单击行的 Select 按钮时发生,但在 GridView 控件处理 Select 操作之前。 |
已排序 |
在单击用于排序的列的超链接后发生,但在 GridView 控件处理排序操作之后。 |
排序 |
在单击用于排序的列的超链接时发生,但在 GridView 控件处理排序操作之前。 |
Unload |
在服务器控件从内存中卸载时发生。(继承自 Control 。) |
所有这些事件都列在 MSDN 上,我在这里列出了一些在我们日常项目中经常使用的事件。
PageIndexChanging
当网格的 AllowPaging
属性设置为 true
时,并且在代码隐藏中触发了 PageIndexChanging
事件。
分页
DataGrid
提供了从数据源显示一组记录(例如,前 10 条)的方法,然后导航到包含下一组 10 条记录的“页面”,依此类推。
通过将 AllowPaging
设置为 true
来启用 DataGrid
中的分页。启用后,网格将显示分页导航按钮,可以是“下一页/上一页”按钮或数字按钮。单击分页导航按钮时,会触发 PageIndexChanged
事件。由程序员在代码中处理此事件。
//AllowPaging="True"
//fires when the property AllowPaging is set to True
GridView2.PageIndex = e.NewPageIndex;
//Datasource method
TempTable();
RowCommand
当按下任何按钮时,DataGrid
会触发 RowCommand
事件。我们可以给命令名任意命名,然后根据这个名称进行检查并执行循环。
//OnRowCommand="GridView6_RowCommand"
//CommandName="view" CommandArgument='<%# Bind("id") %>'
protected void GridView6_RowCommand(object sender, GridViewCommandEventArgs e)
{
//this will check whether the command name is equal to view. If it is
//equal to view the it will go inside the loop.
if (e.CommandName == "view")
{
//to find which row is clicked
int row = int.Parse(e.CommandArgument.ToString());
StringBuilder sb = new StringBuilder();
sb.Append("<script language="'javascript'">\r\n");
//javascript to navigate to view page.
sb.Append(" window.open('View.aspx?id=" + row + "',
null,'width=350,height=300,scrollbars=yes,left=350,top=200,right=5,bottom=5');");
sb.Append("</script>");
if (!this.IsClientScriptBlockRegistered("BindScript"))
{
RegisterClientScriptBlock("openScript", sb.ToString());
}
}
}
RowCreated
当创建新行时,DataGrid
会触发 RowCreate
事件。
//OnRowCreated="GridView3_RowCreated"
protected void GridView3_RowCreated(object sender, GridViewRowEventArgs e)
{
//When a child checkbox is unchecked then the header checkbox will also be unchecked.
if (e.Row.RowType == DataControlRowType.DataRow && (e.Row.RowState ==
DataControlRowState.Normal || e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox chkBxSelect = (CheckBox)e.Row.Cells[1].FindControl("chkselect");
CheckBox chkBxHeader = (CheckBox)this.GridView3.HeaderRow.FindControl("chkHeader");
chkBxSelect.Attributes["onclick"] = string.Format("javascript:ChildClick(
this,'{0}');", chkBxHeader.ClientID);
}
}
RowDeleting
当命令名指定为 Delete 时,DataGrid
会触发 RowDeleting
事件。
//OnRowDeleting="GridView3_RowDeleting"
//CommandName="delete"
protected void GridView3_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
//finding the row index of which row is selected.
int row = e.RowIndex;
//deleteing the temp row(or your delete query that will delete the row from
//the database
Temp.Rows[row].Delete();
//reassigning the datasource
GridView3.DataSource = Temp;
GridView3.DataBind();
}
RowUpdating
当命令名指定为 Update 时,DataGrid
会触发 RowUpdating
事件。
//OnRowUpdating="GridView3_RowUpdating"
CommandName="update"
protected void GridView3_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//maintaining the row index to intial position
GridView3.EditIndex = e.RowIndex;
//reassigning the datasource
GridView3.DataSource = Temp;
GridView3.DataBind();
}
RowEditing
当命令名指定为 Edit 时,DataGrid
会触发 RowEditing
事件。
/OnRowEditing="GridView3_RowEditing"
//CommandName="edit"
protected void GridView3_RowEditing(object sender, GridViewEditEventArgs e)
{
//changing the index of the grid.
GridView3.EditIndex = e.NewEditIndex - 1;
//finding the row of the grid
int row = e.NewEditIndex;
//updating the rows inside the grid
Temp.Rows[row]["name"] = ((TextBox)GridView3.Rows[e.NewEditIndex].FindControl(
"txtname")).Text;
Temp.Rows[row]["gender"] = ((DropDownList)GridView3.Rows[e.NewEditIndex].FindControl(
"ddlgender")).Text;
Temp.Rows[row]["email"] = ((TextBox)GridView3.Rows[e.NewEditIndex].FindControl(
"txtemail")).Text;
Temp.Rows[row]["salary"] = ((TextBox)GridView3.Rows[e.NewEditIndex].FindControl(
"txtsalary")).Text;
Temp.AcceptChanges();
//total of the salary and displaying it in footer.
Total = decimal.Parse(Temp.Compute("sum(Salary)", "Salary>=0").ToString());
//maintaining the total value in the session
Session["Salary"] = Total;
//reassigning the datasource
GridView3.DataSource = Temp;
GridView3.DataBind();
}
RowDatabound
当数据行绑定到 GridView
控件中的数据时,DataGrid
会触发 RowDatabound
事件。
//OnRowDataBound="GridView4_RowDataBound"
protected void GridView4_RowDataBound(object sender, GridViewRowEventArgs e)
{
//Example for grid inside a grid
//to find the row index to the selected row.
int index = e.Row.RowIndex;
//check whether the row type is equal
if (e.Row.RowType == DataControlRowType.DataRow)
{
//assiging datasource for the grid inside the grid.
DataTable tempdt = new DataTable();
tempdt.Columns.Add("Id");
tempdt.Columns.Add("Language", typeof(String));
DataRow dr = tempdt.NewRow();
dr["Id"] = 1;
dr["Language"] = "C";
tempdt.Rows.Add(dr);
DataRow dr1 = tempdt.NewRow();
dr1["Id"] = 2;
dr1["Language"] = "C++";
tempdt.Rows.Add(dr1);
GridView gr = (GridView)(e.Row.FindControl("GridView5"));
if (gr != null)
{
gr.DataSource = tempdt;
gr.DataBind();
}
}
}
排序
网格中的数据通常通过单击列标题进行排序。通过将 AllowSorting
设置为 true
来启用 DataGrid
中的排序。启用后,网格会在每一列的标题中呈现 LinkButton
控件。单击按钮时,会触发网格的 SortCommand
事件。由程序员在代码中处理此事件。由于 DataGrid
始终以数据源中出现的相同顺序显示数据,因此典型的逻辑是先对数据源进行排序,然后将数据重新绑定到网格。
//AllowSorting="True"
//OnSorting="GridView2_Sorting"
//SortExpression="name"
protected void GridView2_Sorting(object sender, GridViewSortEventArgs e)
{
//to check whether to display in ascending order or descending order
if (e.SortExpression.Trim() == this.SortField)
this.SortDirection = (this.SortDirection == "D" ? "A" : "D");
else
this.SortDirection = "A";
this.SortField = e.SortExpression;
TempTable();
}
网格的页眉和页脚
当需要通过选中网格标题中的单个复选框来选中列中的所有复选框时,可以使用此 JavaScript。当我们选中网格标题时,网格内的所有复选框都将被选中,并且如果任何子列被取消选中,标题也将被取消选中。
<script type="text/javascript">
var TotalChkBx;
var Counter;
window.onload = function()
{
TotalChkBx = parseInt('<%= this.GridView3.Rows.Count %>');
Counter = 0;
}
function SelectAll(CheckBox)
{
var TargetBaseControl = document.getElementById('<%= this.GridView3.ClientID %>');
var TargetChildControl = "chkselect";
var Inputs = TargetBaseControl.getElementsByTagName("input");
for(var n = 0; n < Inputs.length; ++n)
if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf(TargetChildControl,0) >= 0)
Inputs[n].checked = CheckBox.checked;
Counter = CheckBox.checked ? TotalChkBx : 0;
}
function ChildClick(CheckBox, HCheckBox)
{
var HeaderCheckBox = document.getElementById(HCheckBox);
if(CheckBox.checked && Counter < TotalChkBx)
Counter++;
else if(Counter > 0)
Counter--;
if(Counter < TotalChkBx)
HeaderCheckBox.checked = false;
else if(Counter == TotalChkBx)
HeaderCheckBox.checked = true;
}
</script>
onclick="javascript:SelectAll(this);"
通过以下代码维护页脚中的值
protected void GridView3_RowDataBound(object sender, GridViewRowEventArgs e)
{
//total in the footer
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[4].Text = this.Total.ToString();
}
}
为了使网格标题保持固定状态,在源代码中使用了一个样式表。
<style type="text/css">.DataGridFixedHeader {
BACKGROUND: url(Images/grid_header.jpg) repeat-x;
POSITION: relative; TOP: expression(this.offsetParent.scrollTop); HEIGHT: 27px }
</style>
<div style="width:80%; height:250px; overflow:auto;" >
<asp:GridView ID="GridView1" runat="server"
Width="100%" AutoGenerateColumns="False"
CellPadding="4" DataKeyNames="id"
ForeColor="#333333" GridLines="None"
OnRowCreated="GridView1_RowCreated"
AllowPaging="True" AllowSorting="True"
OnPageIndexChanging="GridView1_PageIndexChanging" OnSorting="GridView1_Sorting"
PageSize="2" OnRowCommand="GridView1_RowCommand"
OnRowDeleting="GridView1_RowDeleting"
OnRowEditing="GridView1_RowEditing">
....
....
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White"
CssClass="gridHeader DataGridFixedHeader" />
.....
.....
</asp:GridView>
</div>
将 GridView 导出到 Word、Excel 和 PDF
单词
protected void btnword_Click(object sender, EventArgs e)
{
Response.AddHeader("content-disposition",
"attachment;filename=Information.doc");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/vnd.word";
System.IO.StringWriter stringWrite = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
// Create a form to contain the grid
HtmlForm frm = new HtmlForm();
GridView1.Parent.Controls.Add(frm);
frm.Attributes["runat"] = "server";
frm.Controls.Add(GridView1);
frm.RenderControl(htmlWrite);
//GridView1.RenderControl(htw);
Response.Write(stringWrite.ToString());
Response.End();
}
Excel
protected void btnexcel_Click(object sender, EventArgs e)
{
string attachment = "attachment; filename=Information.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/ms-excel";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
// Create a form to contain the grid
HtmlForm frm = new HtmlForm();
GridView1.Parent.Controls.Add(frm);
frm.Attributes["runat"] = "server";
frm.Controls.Add(GridView1);
frm.RenderControl(htw);
//GridView1.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
}
protected void btnpdf_Click(object sender, EventArgs e)
{
Response.Clear();
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
GridView1.RenderControl(htw);
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition",
"attachment; filename=Information.pdf");
Response.Write(sw.ToString());
Response.End();
}
DataGrid、DataList 和 Repeater 之间的区别
DataGrid
、DataList
和 Repeater
都是 ASP.NET 数据 Web 控件。
它们有很多共同点,例如 DataSource
属性、DataBind
方法以及 ItemDataBound
和 ItemCreated
事件。
当您将 DataGrid
的 DataSource
属性分配给 DataSet
时,DataTable
的 DataRow
集合中的每个 DataRow
都分配给一个相应的 DataGridItem
,对于其他两个控件也是如此。但是,为 DataGrid
生成的 HTML 代码有一个 HTML TABLE <ROW>
元素,该元素是为特定的 DataRow
创建的,并且是以表格形式表示,包含列和行。对于 DataList
,它是一个行数组,并且根据选择的模板和 RepeatColumn
属性值,我们可以指定每行 HTML <table>
中应显示多少个 DataSource
记录。简而言之,在 DataGrid
中,每行一个记录,但在 DataList
中,每行可以有五个或六个记录。对于 Repeater
控件,要显示的数据记录取决于指定的模板,生成的唯一 HTML 是由于模板而产生的。
除此之外,DataGrid
内置支持数据的排序、过滤和分页,而使用 DataList
时则不可能实现;对于 Repeater
控件,我们需要编写显式代码来实现分页。
结论
这是我的第二篇文章,如果您有任何疑问,可以参考附带的项目,因为文章中的所有代码都来自该项目。欢迎提出进一步的问题、澄清或指出错误。