Friday, May 27, 2005
Maintaining Control Values in DataGrid Header
The previous post described how I have a DataSet which the DataGrid binds to in order to display the data. The problem with this approach is that each time the .DataBind() method is called, the DataGrid recreates all of the controls from scratch. If controls are placed in the header or footer, then those controls as well are replaced, despite the fact that they are not databound. In order to get around this problem, I needed to save the values of all of the controls before the .DataBind() call and then restore those values after the .DataBind().
Saving the value of a TextBox inside the header is a pain and the code is really ugly:
This recursive function takes a control and looks for useful controls inside all of the children of the control. It saves the important values of each of the TextBox, CheckBox, Panel, and BaseValidator controls so that they can be restored later. Only the controls of those types with a specified ID will be saved. I call this function as follows
Then I wrote a function called LoadControls which is the exact same except the assignment statements go the other way. To use this effectively, I do things in the following order:
I had it set up so that not only were there TextBox controls in the header and footer, but each of them also had a validation control associated with them. If the validation control (server side) rejected the input, then the IsValid was set to False, as one should expect. However, I had the problem that the ValidationSummary control did not show up on the page. There were errors, but the errors were not visible. I finally tracked down the problem to the fact that the validators were reset to their original state during the .DataBind() method. So, I had to include the BaseValidator class in my SaveControls and LoadControls functions in order to remember if each one was valid or not. Then because the page was rendered with the validators in the correct state, everything worked out and the ValidationSummary control knew which messages to display.
Saving the value of a TextBox inside the header is a pain and the code is really ugly:
MyTextBoxText = CType(MyDataGrid.Controls(0).Controls(0).FindControl("MyTextBox"), TextBox).TextDoing this for each textbox leads to some very inelegant code. Instead of doing this, I desired a general function that would save the value for anything that it finds. I ended up with the following function:
Private Sub SaveControls(ByRef ctrl As Control)
Dim con As Control
'Loop through every control inside the one given
For Each con In ctrl.Controls
If con.ID <> "" Then
If TypeOf con Is TextBox Then
ViewState("Saved" & con.ID) = CType(con, TextBox).Text
ElseIf TypeOf con Is CheckBox Then
ViewState("Saved" & con.ID) = CType(con, CheckBox).Checked
ElseIf TypeOf con Is Panel Then
ViewState("Saved" & con.ID) = CType(con, Panel).Visible
ElseIf TypeOf con Is BaseValidator Then
ViewState("Saved" & con.ID) = CType(con, BaseValidator).IsValid
End If
End If
SaveControls(con) 'Now look inside this control for more controls
Next
End Sub
This recursive function takes a control and looks for useful controls inside all of the children of the control. It saves the important values of each of the TextBox, CheckBox, Panel, and BaseValidator controls so that they can be restored later. Only the controls of those types with a specified ID will be saved. I call this function as follows
SaveControls(MyDataGrid.Controls(0).Controls(0))to save the values of each of the important controls in the header of the DataGrid. (See the previous posts for how to do the footer).
Then I wrote a function called LoadControls which is the exact same except the assignment statements go the other way. To use this effectively, I do things in the following order:
- SaveControls (for header, footer, and edit row)
- DataBind
- LoadControls (for header, footer, and edit row)
I had it set up so that not only were there TextBox controls in the header and footer, but each of them also had a validation control associated with them. If the validation control (server side) rejected the input, then the IsValid was set to False, as one should expect. However, I had the problem that the ValidationSummary control did not show up on the page. There were errors, but the errors were not visible. I finally tracked down the problem to the fact that the validators were reset to their original state during the .DataBind() method. So, I had to include the BaseValidator class in my SaveControls and LoadControls functions in order to remember if each one was valid or not. Then because the page was rendered with the validators in the correct state, everything worked out and the ValidationSummary control knew which messages to display.
Comments:
<< Home
Looking back, this method needlessly bloats the ViewState sent to the page, as there is no reason to remember this information between page loads, only over the .DataBind() method. A better way would be to declare a variable that is global within the class, such as:
Protected SavedControls As New Hashtable
Then instead of ViewState in the subroutines, use SavedControls.
Post a Comment
Protected SavedControls As New Hashtable
Then instead of ViewState in the subroutines, use SavedControls.
<< Home