(Updated 10/29 to include ASP.Net example
A great thanks to Matt Berseth for his post on subclassing the GridView to show footers even when the GridView has no records. I used a C# to VB.Net converter to convert his excellent example and the net result is the code below (and includes the tweak/fix for persisting the Footer on PostBack). A few pecularities I noticed about using the Footer.
- I could not use two-way binding with my ObjectDataSource in the footer so I used the traditional code-behind approach with FindControl (insert does not use the DataSource at all)
- to find your controls you have to use MyGridView.Footer.FindControl(“aTextBox”)
- to hide/show the footer I added buttons to the header and footer that fire the GridView.RowCommand (note, the Insert also uses this technique)
Public Class MyGridView
Inherits GridView
Protected Overloads Overrides Function CreateChildControls(ByVal dataSource As System.Collections.IEnumerable, ByVal dataBinding As Boolean) As Integer
Dim numRows As Integer = MyBase.CreateChildControls(dataSource, dataBinding)
'no data rows created, create empty table if enabled
If numRows = 0 AndAlso ShowWhenEmpty Then
'create table
Dim table As New Table()
table.ID = Me.ID
'convert the exisiting columns into an array and initialize
Dim fields As DataControlField() = New DataControlField(Me.Columns.Count - 1) {}
Me.Columns.CopyTo(fields, 0)
If Me.ShowHeader Then
'create a new header row
Dim headerRow As GridViewRow = MyBase.CreateRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
Me.InitializeRow(headerRow, fields)
table.Rows.Add(headerRow)
End If
'create the empty row
Dim emptyRow As New GridViewRow(-1, -1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal)
Dim cell As New TableCell()
cell.ColumnSpan = Me.Columns.Count
cell.Width = Unit.Percentage(100)
If Not [String].IsNullOrEmpty(EmptyDataText) Then
cell.Controls.Add(New LiteralControl(EmptyDataText))
End If
If Me.EmptyDataTemplate IsNot Nothing Then
EmptyDataTemplate.InstantiateIn(cell)
End If
emptyRow.Cells.Add(cell)
table.Rows.Add(emptyRow)
If Me.ShowFooter Then
'create footer row
'Dim footerRow As GridViewRow = MyBase.CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Normal)
_footerRow = MyBase.CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Normal)
Me.InitializeRow(footerRow, fields)
table.Rows.Add(footerRow)
End If
Me.Controls.Clear()
Me.Controls.Add(table)
End If
Return numRows
End Function
<Category("Behaviour")> _
<Themeable(True)> _
<Bindable(BindableSupport.No)> _
Public Property ShowWhenEmpty() As Boolean
Get
If ViewState("ShowWhenEmpty") Is Nothing Then
ViewState("ShowWhenEmpty") = False
End If
Return CBool(ViewState("ShowWhenEmpty"))
End Get
Set(ByVal value As Boolean)
ViewState("ShowWhenEmpty") = value
End Set
End Property
Protected _footerRow As GridViewRow = Nothing
Public Overloads Overrides ReadOnly Property FooterRow() As GridViewRow
Get
Return IIf(_footerRow Is Nothing, MyBase.FooterRow, _footerRow)
End Get
End Property
End Class
<asp:ValidationSummary ID="vsumDocErrors" runat="server" />
<cc1:MyGridView ID="gvwDocs" runat="server" AutoGenerateColumns="False" DataSourceID="dsDocs"
DataKeyNames="ID" ShowWhenEmpty="true">
<EmptyDataTemplate>
No related data elements</EmptyDataTemplate>
<Columns>
<asp:TemplateField>
<headertemplate>
<asp:ImageButton runat="server" CommandName="Add" AlternateText="Add New Item" ImageUrl="../images/add.png"
OnPreRender="AddButton_PreRender"/>
</headertemplate>
<itemtemplate>
<asp:ImageButton runat="server" CommandName="Select" AlternateText="View Item" ImageUrl="../images/MGlass.png" />
<asp:ImageButton ID="btnDelDoc" runat="server" CommandName="Delete" AlternateText="Delete Item"
ImageUrl="../images/cross.png"
visible="<%# (UserCanEdit) AndAlso (gvwDocs.ShowFooter = False) %>"
OnClientClick='<%# DataBinder.Eval(Container.DataItem, "Description", "return confirm(""Are you sure you want to delete document: [{0}] ?"");") %>' />
</itemtemplate>
<footertemplate>
<asp:ImageButton ID="btnFooterCancel" runat="server" CommandName="CancelAdd" AlternateText="Cancel Add" CausesValidation="false"
ImageUrl="../images/Cancel.png"
OnClientClick="doCheck = false;" />
<asp:ImageButton ID="ImageButton1" runat="server" CommandName="Insert" CommandArguement="Insert" AlternateText="Save Item"
ImageUrl="../images/disk.png"
OnClientClick="doCheck = false;" />
</footertemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Document Name">
<itemtemplate>
<asp:Label runat="server" Text='<%# CType(Container.DataItem, MyProj.Lib.Document).Description %>'></asp:Label>
</itemtemplate>
<footertemplate>
<div><asp:Label runat="server" AssociatedControlID="inDocument" CssClass="Label" Style="width:120px">Select File</asp:Label>
<asp:RequiredFieldValidator runat="server" Display="Dynamic" ErrorMessage="File has not been selected" controlToValidate="inDocument">*</asp:RequiredFieldValidator></div>
<asp:FileUpload runat="server" id="inDocument" Style="width:500px;font-size:x-small;" />
<asp:RegularExpressionValidator id="vldDocument" runat="server" OnLoad="Setup_Doc_Validator" ControlToValidate="inDocument" />
<div><asp:Label runat="server" AssociatedControlID="inDocName" CssClass="Label" Style="width:120px">Friendly Name</asp:Label>
<asp:TextBox runat="server" id="inDocName" Columns="40" Style="font-size:x-small" />(optional)</div>
</footertemplate>
</asp:TemplateField>
<asp:BoundField DataField="CreatedBy" HeaderText="Created By" />
</Columns>
</cc1:MyGridView>
<asp:ObjectDataSource ID="dsDocs" runat="server" SelectMethod="GetDocumentsByAgency"
TypeName="MyProj.Lib.DocumentDAL" DeleteMethod="Delete" DataObjectTypeName="MyProj.Lib.Document">
<SelectParameters>
<asp:QueryStringParameter Name="intAgencyID" QueryStringField="PID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
7 comments:
Nice article. How would you bind a list of values to a dropdownlist in the empty row?
Thanks! I couldn't post the code in the comment, so I created a new post. See Binding in Footer
supper difficult.
I made more easy ..
Simply on the query, add a blank row (UNION SELECT 0, .. tipically where 0 is the key).
This will put the blank row on, now you only need to make invisible
onDatabound,
Using this way, you will ever have a Footer row available to put on the insert controls.
Alejandro Barrada MartÃn
Asp.Net Blog
please check this post also as a solution for this issue
http://ledomoon.blogspot.com/2009/04/show-grid-view-header-and-footer-when.html
Thanks, Thanks too much!!
I have a problem , when gridview have event rowdatabound this execute first and the controls no works , ShowWhenEmpty execute after rowdatabound event
Post a Comment