Thursday, August 14, 2008

Persisting dynamically built GridView's state and data

As I promised, there will be one more post about creating dynamically a GridView.
Let’s now see what happens on a Post Back ?
Our GridView created dynamically with template fields is lost. As we know the GridView has a property called “EnableViewState”. If we set this property to “true” we can expect our GridView and it’s data to be persisted after the post back. But that’s not the case. The “EnableViewState” itself saves only the data in the cells of the GridView to the ViewState, so we will again see nothing. What we have to do (something we should do to every control we have somehow constructed dynamically) is to build the GridView over and over again every time the Page is sent back to the server. We have to do this on an event where we still have the ability to change the Page’s layout and controls included in it.
For example if we are creating an UserControl we should reconstruct the GridView on it’s Init event ( http://msdn.microsoft.com/en-us/library/system.web.ui.control.init.aspx ). If we are doing this in a Web Page we should place our code in the PreInit event ( http://msdn.microsoft.com/en-us/library/system.web.ui.page.preinit.aspx ).
Now we have accomplished our task to save the GridView after Post Back. Unfortunately, creating dynamically controls needs much more coding, than creating them statically.
The other thing I would like to share is very simple. It answers the question ‘How do we handle the edit of such a custom grid ?’
We will create our own column with Edit/Update/Cancel link buttons. We place a code like this in the GridView control:
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="lbEdit" CommandName="Edit" Text="Edit" runat="server" />

</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="lbUpdate" CommandName="Update" Text="Update" runat="server" />

<asp:LinkButton ID="lbCancel" CommandName="Cancel" Text="Cancel" runat="server" />

</EditItemTemplate>
</asp:TemplateField>

Please, note that we could have just set the property of the GridView “AutoGenerateEditButton” to true to let the framework generate such a column for us.
No we have to handle the events for Update, Cancel, Edit adding code again in the GridView for the events, like this:
OnRowEditing="gv_RowEditing"
OnRowCancelingEdit="gv_RowCancelingEdit"
OnRowUpdating="gv_RowUpdating"


Now the only thing left is to implement the above methods in the code behind to handle the raised events. Sample code goes below:
protected void gv_RowEditing(object sender, GridViewEditEventArgs e)
{
gv.EditIndex = e.NewEditIndex; // set the edit index, which causes
// the GridView to enter it’s edit
// mode
// Rebind data here

}
protected void gv_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
gv.EditIndex = -1; // Clear the edit index, and return
// to change the mode again.
// Rebind data here

}
protected void gv_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DataTable dt = TableGV; // This is my object behind the
// GridView which holds it’s data.
// And I want it updated.

GridViewRow row = gv.Rows[e.RowIndex];
for (int i = 0; i < dt.Columns.Count; i++)
{
dt.Rows[gv.EditIndex][i] = ((TextBox)(row.Cells[i + 1].Controls[0])).Text.Trim(); // Get the data from the GridViewRow
}
gv.EditIndex = -1; // Again change the mode
// Rebind data here

}

That’s all, we now have a complete editable custom dynamically created GridView Control.