I have a simple ASP page with a data-bound grid (bound to an object source). The grid is within the page of a wizard and has a 'select' checkbox for each row.
In one stage of the wizard, I bind the GridView
:
protected void Wizard1_NextButtonClick(object sender, WizardNavigationEventArgs e)
{
...
// Bind and display matches
GridViewMatches.EnableViewState = true;
GridViewMatches.DataSource = getEmailRecipients();
GridViewMatches.DataBind();
...
And when the finish button is clicked, I iterate through the rows and check what's selected:
protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
{
// Set the selected values, depending on the checkboxes on the grid.
foreach (GridViewRow gr in GridViewMatches.Rows)
{
Int32 personID = Convert.ToInt32(gr.Cells[0].Text);
CheckBox selected = (CheckBox) gr.Cells[1].FindControl("CheckBoxSelectedToSend");
...
But at this stage GridViewMatches.Rows.Count
is 0. I don't re-bind the grid - I shouldn't need to, should I? I expect the ViewState
to maintain the state (also, if I do rebind the grid, my selection checkboxes will be cleared).
NB: This page also dynamically adds user controls in OnInit
method. I have heard that it might mess with the view state, but as far as I can tell, I am doing it correctly and the ViewState
for those added controls seems to work (values have persisted between post-backs.)
Could this be to do with the fact I am setting the data source programmatically? I wondered if the asp engine was data binding the grid during the page lifecycle to a data source that was not yet defined. (In a test page, the GridView
is 'automatically' data-bound. I don't want the grid to re-bound I just want the values from the ViewState
from the previous post!
Also, I have this in the asp header: ViewStateEncryptionMode="Never" - this was to resolve an occasional 'Invalid Viewstate Validation MAC' message
For reference, my GridView is defined as follows:
<asp:GridView ID="GridViewMatches" runat="server" AllowSorting="True" AutoGenerateColumns="False"
BackColor="White" BorderColor="#E7E7FF" BorderStyle="None" BorderWidth="1px" CellPadding="3"
OnDataBinding="GridViewMatches_OnBinding">
<Columns>
<asp:BoundField DataField="PersonID"><ItemStyle CssClass="hidden"/></asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="CheckBoxSelectedToSend" runat="server"
Checked='<%# DataBinder.Eval(Container.DataItem, "SelectedToSend") %>'/>
</ItemTemplate>
...
Iterating the controls in the PreInit event (to detect if the 'add another control' or 'remove another control' button was pressed) invalidates the view state!
Here is the method called from PreInit, from Ryan Farley's blog post, Determining the Control that Caused a PostBack:
public static Control GetPostBackControl(Page page) { Control control = null; string ctrlname = page.Request.Params.Get("__EVENTTARGET"); if (ctrlname != null && ctrlname != string.Empty) { control = page.FindControl(ctrlname); } else { foreach (string ctl in page.Request.Form) { Control c = page.FindControl(ctl); if (c is System.Web.UI.WebControls.Button) { control = c; break; } } } return control; }
If the first line is uncommented, the viewstate is maintained.