Search Wiki:
Resource Page Description
A more elegant solution to display GridView header and footer when the data source is empty.

I think the need to always show the header and footer of a GridView is pretty common.
When I first ran into this problem, I went to Google and found lots of content about this.
Some suggest tampering with the data source to add an extra row if it’s empty. Others show overriding the CreateChildControls method.

I was not satisfied with either of these solutions. I didn’t like that dirty feeling I had by tampering with the data source. And I didn’t like overriding the CreateChildControls method because it simply didn’t work of me anyway. This solution only gave the appearance of the header and footer existing. I ran into issues because I was programmatically adding controls to the header. Upon postback, if the data source was empty, the control hierarchy would not be the same as before thus causing an error.


I blogged about this here
http://weblogs.asp.net/joewrobel/archive/2008/01/30/a-more-elegant-solution-to-display-gridview-header-and-footer-when-the-data-source-is-empty.aspx
Last edited Jan 31 2008 at 3:52 AM  by robolize, version 3
Comments
Boretskiy wrote  Feb 14 2008 at 7:50 PM  
Thanks a lot for you post it was helpful me. But I added to your variant some changes for correct raising event and registration controls.
Below you can see full version.

private GridViewRow _headerRow;
private GridViewRow _footerRow;

[Category("Behavior")]
[Themeable(true)]
[Bindable(BindableSupport.No)]
public bool ShowHeaderWhenEmpty
{
get { return _showHeaderWhenEmpty; }
set { _showHeaderWhenEmpty = value; }
}

[Category("Behavior")]
[Themeable(true)]
[Bindable(BindableSupport.No)]
public bool ShowFooterWhenEmpty
{
get { return _showFooterWhenEmpty; }
set { _showFooterWhenEmpty = value; }
}

public override GridViewRow HeaderRow
{
get { return base.HeaderRow ?? _headerRow; }
}

public override GridViewRow FooterRow
{
get { return base.FooterRow ?? _footerRow; }
}

protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
int rows = base.CreateChildControls(dataSource, dataBinding);

// no data rows created, create empty table if enabled
if (rows == 0 && (ShowFooterWhenEmpty || ShowHeaderWhenEmpty))
{
// create the table
Table table = CreateChildTable();

Controls.Clear();
Controls.Add(table);

DataControlField[] fields;
if (AutoGenerateColumns)
{
PagedDataSource source = new PagedDataSource();
source.DataSource = dataSource;

ICollection autoGeneratedColumns = CreateColumns(source, true);
fields = new DataControlField[autoGeneratedColumns.Count];
autoGeneratedColumns.CopyTo(fields, 0);
}
else
{
fields = new DataControlField[Columns.Count];
Columns.CopyTo(fields, 0);
}

TableRowCollection newRows = table.Rows;
if (ShowHeaderWhenEmpty)
{
// create a new header row
_headerRow = CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
InitializeRow(_headerRow, fields, newRows);
}

// create the empty row
GridViewRow emptyRow = new GridViewRow(-1, -1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);
TableCell cell = new TableCell();
cell.ColumnSpan = fields.Length;
cell.Width = Unit.Percentage(100);

// respect the precedence order if both EmptyDataTemplate
// and EmptyDataText are both supplied ...
if (EmptyDataTemplate != null)
{
EmptyDataTemplate.InstantiateIn(cell);
}
else if (!string.IsNullOrEmpty(EmptyDataText))
{
cell.Controls.Add(new LiteralControl(EmptyDataText));
}

emptyRow.Cells.Add(cell);
GridViewRowEventArgs e = new GridViewRowEventArgs(emptyRow);
OnRowCreated(e);

newRows.Add(emptyRow);

emptyRow.DataBind();
OnRowDataBound(e);
emptyRow.DataItem = null;

if (ShowFooterWhenEmpty)
{
// create footer row
_footerRow = CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Normal);
InitializeRow(_footerRow, fields, newRows);
}

}

return rows;
}

private void InitializeRow(GridViewRow row, DataControlField[] fields, TableRowCollection newRows)
{
GridViewRowEventArgs e = new GridViewRowEventArgs(row);
InitializeRow(row, fields);
OnRowCreated(e);

newRows.Add(row);

row.DataBind();
OnRowDataBound(e);
row.DataItem = null;
}

rkaltenstein wrote  Mar 17 2008 at 1:56 AM  
This was a big help. Thanks. Noticed your comment about counting the data items. Since you only ever test whether there's more than one, you could just see whether you can move to a fist one and then reset the enumerator:

bool anyItems = data.GetEnumerator().MoveNext();
data.GetEnumerator().Reset();

projammer wrote  Jun 28 2008 at 7:08 PM  
Why not just add a table in. I have text boxes for users to add things at the bottom of the would be table. So instead of going through all of this, I used the EmptyDataTemplate. I did not name anything since there is no need in calling it. Here is the code.

<EmptyDataTemplate>
<asp:Table ID="tblEmptyHeadCount" runat="server" Width="100%">
<asp:TableRow ID="TableRow17" runat="server" HorizontalAlign="right" Width="100%">
<asp:TableCell ID="TableCell42" runat="server" Width="15%"></asp:TableCell>
<asp:TableCell ID="TableCell43" runat="server" Width="40%" HorizontalAlign="center">
<asp:Label ID="lbl1" runat="server" Text="Position"></asp:Label>
</asp:TableCell>
<asp:TableCell ID="TableCell48" runat="server" Width="15%" HorizontalAlign="center">
<asp:Label ID="Label6" runat="server" Text="FTE Salary"></asp:Label>
</asp:TableCell>
<asp:TableCell ID="TableCell49" runat="server" Width="10%" HorizontalAlign="center">
<asp:Label ID="Label7" runat="server" Text="HC"></asp:Label>
</asp:TableCell>
<asp:TableCell ID="TableCell50" runat="server" Width="20%" HorizontalAlign="center">
</asp:TableCell>
</asp:TableRow>
</asp:Table>

</EmptyDataTemplate>

jeremylei wrote  Jul 3 2008 at 4:35 AM  
Hi There.
Just thought I should add some code for you as your example will not work with the standard .NET datatables that contain non-null constraints etc. This code is within the 'PerformDataBinding' Override.

//If it's a DataView, it will work without having to handle the MustAddARow event.
if (data.GetType() == typeof(DataView))
{
DataView dv = (DataView)data;
//Create a table with the same schema as data, but with no constraints
DataTable dt = new DataTable(dv.Table.TableName);
//copy columns
foreach(DataColumn dc in dv.Table.Columns)
{
dt.Columns.Add(dc.ColumnName);
}
//Add a row and use that new view.
dt.Rows.Add(dt.NewRow());
dv = new DataView(dt);
base.PerformDataBinding(dv.Table.DefaultView);
return;
}
else
{
//If you are using some custom object, you need to handle this event.
base.PerformDataBinding(OnMustAddARow(data));
return;
}

Echilon wrote  Jan 23 2009 at 11:53 AM  
Cheers, without knowing I had non null constraints.

SSY wrote  Sep 16 2009 at 12:08 PM  
Hi,
I am binding the gridview to a generic list. How can I show header and footer when there is no data.

Thanks a lot in advance!
SSY

WaleedMohamed wrote  Oct 8 2009 at 11:07 PM  
please check this post also hope be useful in this issue
http://ledomoon.blogspot.com/2009/04/show-grid-view-header-and-footer-when.html

Updating...
Page view tracker