ASP.NET GridView 第二个标题行跨越主标题行
Posted
技术标签:
【中文标题】ASP.NET GridView 第二个标题行跨越主标题行【英文标题】:ASP.NET GridView second header row to span main header row 【发布时间】:2010-09-23 19:19:21 【问题描述】:我有一个 ASP.NET GridView,它的列如下所示:
| Foo | Bar | Total1 | Total2 | Total3 |
是否可以在两行上创建一个像这样的标题?
| | Totals |
| Foo | Bar | 1 | 2 | 3 |
每一行中的数据将保持不变,因为这只是为了美化标题并减少网格占用的水平空间。
在重要的情况下,整个 GridView 都是可排序的。我不打算让添加的“总计”跨越列具有任何排序功能。
编辑:
根据下面给出的一篇文章,我创建了一个继承自 GridView 的类,并在其中添加了第二个标题行。
namespace CustomControls
public class TwoHeadedGridView : GridView
protected Table InnerTable
get
if (this.HasControls())
return (Table)this.Controls[0];
return null;
protected override void OnDataBound(EventArgs e)
base.OnDataBound(e);
this.CreateSecondHeader();
private void CreateSecondHeader()
GridViewRow row = new GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal);
TableCell left = new TableHeaderCell();
left.ColumnSpan = 3;
row.Cells.Add(left);
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = this.Columns.Count - 3;
totals.Text = "Totals";
row.Cells.Add(totals);
this.InnerTable.Rows.AddAt(0, row);
如果您像我一样是 ASP.NET 新手,我还应该指出您需要:
1) 通过在您的网络表单中添加这样的一行来注册您的课程:
<%@ Register TagPrefix="foo" NameSpace="CustomControls" Assembly="__code"%>
2) 将之前标记中的 asp:GridView 更改为 foo:TwoHeadedGridView。不要忘记结束标记。
另一个修改:
您也可以在不创建自定义类的情况下执行此操作。
只需为网格的 DataBound 事件添加一个事件处理程序,如下所示:
protected void gvOrganisms_DataBound(object sender, EventArgs e)
GridView grid = sender as GridView;
if (grid != null)
GridViewRow row = new GridViewRow(0, -1,
DataControlRowType.Header, DataControlRowState.Normal);
TableCell left = new TableHeaderCell();
left.ColumnSpan = 3;
row.Cells.Add(left);
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = grid.Columns.Count - 3;
totals.Text = "Totals";
row.Cells.Add(totals);
Table t = grid.Controls[0] as Table;
if (t != null)
t.Rows.AddAt(0, row);
自定义控件的优点是您可以在 Web 表单的设计视图上看到额外的标题行。不过,事件处理程序方法要简单一些。
【问题讨论】:
更新后的答案对我有很大帮助,感谢您花时间记录它 这里相同 - 感谢您填写空白 注意 - 我发现我必须添加row.TableSection = TableRowSection.TableHeader
才能使代码正常工作
【参考方案1】:
我采用了接受的答案方法,但将标题添加到现有的 GridView 而不是自定义继承的 GridView。
绑定 GridView 后,我执行以下操作:
/*Create header row above generated header row*/
//create row
GridViewRow row = new GridViewRow(0, -1, DataControlRowType.Header, DataControlRowState.Normal);
//spanned cell that will span the columns I don't want to give the additional header
TableCell left = new TableHeaderCell();
left.ColumnSpan = 6;
row.Cells.Add(left);
//spanned cell that will span the columns i want to give the additional header
TableCell totals = new TableHeaderCell();
totals.ColumnSpan = myGridView.Columns.Count - 3;
totals.Text = "Additional Header";
row.Cells.Add(totals);
//Add the new row to the gridview as the master header row
//A table is the only Control (index[0]) in a GridView
((Table)myGridView.Controls[0]).Rows.AddAt(0, row);
/*fin*/
【讨论】:
【参考方案2】:This article 应该为您指明正确的方向。您可以以编程方式创建行并将其添加到位置 0 的集合中。
【讨论】:
谢谢!我使用该链接提出了解决方案。【参考方案3】:在VB.NET中选择使用RowDataBound方法的注意
如果您最终弹出了太多额外的标题行,请添加一个 If 语句,该语句仅在 gridview 的标题行没有任何内容(意味着它是当前被绑定的行)时才继续
If grid.HeaderRow Is Nothing Then
【讨论】:
【参考方案4】:您必须创建一个扩展 gridview 的类,然后覆盖 CreateRow 方法。
尝试以this 为起点
【讨论】:
【参考方案5】:添加行后添加t.EnableViewState = false;
:
Dim t As Table = TryCast(grid.Controls(0), Table)
If t IsNot Nothing Then
t.Rows.AddAt(0, row)
End If
t.EnableViewState = false;
【讨论】:
【参考方案6】:请参考https://***.com/a/9333714/1060656
我创建了这个解决方案示例
要在本地系统中运行,需要创建 2 个文件(一个用于控件,一个用于 aspx),您可以创建一个项目或 2 个项目。
-
GridViewPlus ==> 控件类
GridViewPlusCustomHeaderRows ==> 保存自定义标头类的集合
CustomHeaderEventArgs ==> 创建自定义标题行时的事件参数
aspx 文件 ==> 测试程序
public class GridViewPlus : GridView
public event EventHandler<CustomHeaderEventArgs> CustomHeaderTableCellCreated;
private GridViewPlusCustomHeaderRows _rows;
public GridViewPlus() : base ()
_rows = new GridViewPlusCustomHeaderRows();
/// <summary>
/// Allow Custom Headers
/// </summary>
public bool ShowCustomHeader get; set;
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
[MergableProperty(false)]
public GridViewPlusCustomHeaderRows CustomHeaderRows
get return _rows;
protected virtual void OnCustomHeaderTableCellCreated(CustomHeaderEventArgs e)
EventHandler<CustomHeaderEventArgs> handler = CustomHeaderTableCellCreated;
// Event will be null if there are no subscribers
if (handler != null)
// Use the () operator to raise the event.
handler(this, e);
protected override void OnRowCreated(GridViewRowEventArgs e)
if (ShowCustomHeader && e.Row.RowType == DataControlRowType.Header) return;
base.OnRowCreated(e);
protected override void PrepareControlHierarchy()
//Do not show the Gridview header if show custom header is ON
if (ShowCustomHeader) this.ShowHeader = false;
base.PrepareControlHierarchy();
//Safety Check
if (this.Controls.Count == 0)
return;
bool controlStyleCreated = this.ControlStyleCreated;
Table table = (Table)this.Controls[0];
int j = 0;
if (CustomHeaderRows ==null )return ;
foreach (TableRow tr in CustomHeaderRows)
OnCustomHeaderTableCellCreated(new CustomHeaderEventArgs(tr,j));
table.Rows.AddAt(j, tr);
tr.ApplyStyle(this.HeaderStyle);
j++;
public class GridViewPlusCustomHeaderRows : System.Collections.CollectionBase
public GridViewPlusCustomHeaderRows()
public void Add(TableRow aGridViewCustomRow)
List.Add(aGridViewCustomRow);
public void Remove(int index)
// Check to see if there is a widget at the supplied index.
if (index > Count - 1 || index < 0)
// If no widget exists, a messagebox is shown and the operation
// is cancelled.
throw (new Exception("Index not valid"));
else
List.RemoveAt(index);
public TableRow Item(int Index)
// The appropriate item is retrieved from the List object and
// explicitly cast to the Widget type, then returned to the
// caller.
return (TableRow)List[Index];
public class CustomHeaderEventArgs : EventArgs
public CustomHeaderEventArgs(TableRow tr ,int RowNumber )
tRow = tr;
_rownumber = RowNumber;
private TableRow tRow;
private int _rownumber = 0;
public int RowNumber get return _rownumber;
public TableRow HeaderRow
get return tRow;
set tRow = value;
public partial class _Default : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
Example1();
GridViewExtension1.CustomHeaderTableCellCreated += new EventHandler<CustomHeaderEventArgs>(GridViewExtension1_CustomHeaderTableCellCreated);
void GridViewExtension1_CustomHeaderTableCellCreated(object sender, CustomHeaderEventArgs e)
TableRow tc = (TableRow)e.HeaderRow;
tc.BackColor = System.Drawing.Color.AliceBlue;
private void Example1()
System.Data.DataTable dtSample = new DataTable();
DataColumn dc1 = new DataColumn("Column1",typeof(string));
DataColumn dc2 = new DataColumn("Column2",typeof(string));
DataColumn dc3 = new DataColumn("Column3",typeof(string));
DataColumn dc4 = new DataColumn("Column4",typeof(string));
// DataColumn dc5 = new DataColumn("Column5",typeof(string));
dtSample.Columns.Add(dc1);
dtSample.Columns.Add(dc2);
dtSample.Columns.Add(dc3);
dtSample.Columns.Add(dc4);
// dtSample.Columns.Add(dc5);
dtSample.AcceptChanges();
for (int i = 0; i < 25; i++)
DataRow dr = dtSample.NewRow();
for (int j = 0; j < dtSample.Columns.Count; j++)
dr[j] = j;
dtSample.Rows.Add(dr);
dtSample.AcceptChanges();
//GridViewExtension1.ShowHeader = false;
GridViewExtension1.ShowCustomHeader = true;
/*
*=======================================================================
* |Row 1 Cell 1 | Row 1 Col 2 (Span=2) | Row 1 Col 3 |
* | | | |
*=======================================================================
* |Row 2 Cell 1 | | | |
* | | Row 2 Col 2 | Row 2 Col 3 |Row 2 Col 4 |
*=======================================================================
*
*
*
*
* */
// SO we have to make 2 header row as shown above
TableRow TR1 = new TableRow();
TableCell tcR1C1 = new TableCell();
tcR1C1.Text = "Row 1 Cell 1";
tcR1C1.ColumnSpan = 1;
TR1.Cells.Add(tcR1C1);
TableCell tcR1C2 = new TableCell();
tcR1C2.Text = "Row 1 Cell 2";
tcR1C2.ColumnSpan = 2;
TR1.Cells.Add(tcR1C2);
TableCell tcR1C3 = new TableCell();
tcR1C3.Text = "Row 1 Cell 3";
tcR1C3.ColumnSpan = 1;
TR1.Cells.Add(tcR1C3);
GridViewExtension1.CustomHeaderRows.Add(TR1);
TableRow TR2 = new TableRow();
TableCell tcR2C1 = new TableCell();
tcR2C1.Text = "Row 2 Cell 1";
tcR2C1.ColumnSpan = 1;
TR2.Cells.Add(tcR2C1);
TableCell tcR2C2 = new TableCell();
tcR2C2.Text = "Row 2 Cell 2";
tcR2C2.ColumnSpan = 1;
TR2.Cells.Add(tcR2C2);
TableCell tcR2C3 = new TableCell();
tcR2C3.Text = "Row 2 Cell 3";
tcR2C3.ColumnSpan = 1;
TR2.Cells.Add(tcR2C3);
TableCell tcR2C4 = new TableCell();
tcR2C4.Text = "Row 2 Cell 4";
tcR2C4.ColumnSpan = 1;
TR2.Cells.Add(tcR2C4);
GridViewExtension1.CustomHeaderRows.Add(TR2);
GridViewExtension1.DataSource = dtSample;
GridViewExtension1.DataBind();
【讨论】:
【参考方案7】:我想做一个类似的任务,但需要标题内的可点击按钮 - 在这种情况下,以上都不起作用,因为事件处理程序没有连接(由于事件的顺序)。最后,我在网格视图的相应模板字段中使用了 headertemplate 标记。 html 看起来有点臃肿,但事件保持不变,无需额外的代码。例如
<asp:TemplateField >
<HeaderTemplate>
<div>
<div style="text-align: center;padding-bottom: 5px;">
text
</div>
<div>
<asp:Button ID="Button1" runat="server" Text="Apply to all" ToolTip="Apply to all - Special Bolt On" CssClass="sub_button input_btn_5" OnClick="ApplyButton1_Click" />
</div>
</div>
</HeaderTemplate>
<ItemTemplate>....
【讨论】:
以上是关于ASP.NET GridView 第二个标题行跨越主标题行的主要内容,如果未能解决你的问题,请参考以下文章
如何使用C#和ASP.NET将数据从Gridview行解析到另一个页面
使用asp.net gridview和c#从phpmyadmin数据库显示图像
使用可折叠/可扩展行创建 gridview C# asp.net
SweetAlert2 ASP.NET Gridview 删除行确认