views:

1009

answers:

1

Hi all,

Apologies in advance for the long-winded post, but I'm having some trouble with a .NET page I'm building.

END QUESTION: How can I check the 'Checked' property of a dynamically-created checkbox during the Page_Load subroutine?

DETAILS: Basically, I have a VB.NET page that creates some table rows dynamically, based on a number selected by the user. So, for example, if the user selects "3" from a dropdown list, the page posts back and creates three table rows. Each row contains a couple of textboxes, a dropdown list, and a checkbox (which are all .NET form controls rather than plain HTML controls, I should point out).

Typically, the user would enter a few details into the form controls, and click the 'Submit' button, after which the page iterates through each row, and inserts the data into a SQL Server table.

But if the user ticks the checkbox for that row, this signifies that the page is to ignore that row, and NOT insert that row of data into the database when the user clicks 'Submit'.

This works well, but there is a problem. If the user clicks 'Submit' and some of the values entered into the form controls are invalid (so, for example, the user didn't enter their name) then the page won't submit the data, and instead, shows an error to the user informing them of the values they need to change. But if the user creates three rows, for example, but decides to "ignore" the third row (by ticking the checkbox) then when the page posts back, finds some invalid entries, and re-shows the form to the user to allow them to correct any errors, I'd rather the page didn't render the third row altogether. After all, they chose to create three rows originally, but then decided that they only needed two. So it makes sense that the third row is not recreated.

To start with, I simply used code similar to the following within my Page_Load subroutine:

If objCheckbox.Checked = False
   ' Render the row, and recreate the dynamic controls '
Else
   ' Dont render the row or any of the controls '
End If

But what seemed to happen was that objCheckbox.Checked was always returning False, even when the checkbox was ticked. Once the page had loaded, the table rows had rendered again, and the tick was present in the checkbox, so it's not like the value was lost on postback. But at the point I check whether the checkbox is ticked, it always returns False, rendering a table row that the user doesn't need.

Does anyone know how to get round this problem? I've read lots of articles about the .NET ViewState, and the page lifecycle, but I've yet to find a solution that works. I simply need to be able to check if a checkbox is ticked before re-creating some dynamic controls.

I tried this alternative code, which utilises the ViewState, but to no avail:

If objIgnoreCheckbox.ViewState("Checked") = False Then
   ' Render the row, and recreate the dynamic controls '
Else
   ' Dont render the row or any of the controls '
End If

When doing this, I get the following error:

'System.Web.UI.Control.Protected Overridable ReadOnly Property ViewState() As System.Web.UI.StateBag' is not accessible in this context because it is 'Protected'.

So I tried to create a custom class, that inherited from Checkbox, and tried to override the ViewState property to make it public, so that it can be read from:

Public Class CheckboxControl

    ' Inherits all Checkbox properties and methods '
    Inherits Checkbox

    ' Create the public ViewState property '        
    Public Overrides ReadOnly Property ViewState As StateBag

        Get
            Dim objChecked As Object = ViewState("Checked")
            If Not (IsNothing(objChecked)) Then
                Return objChecked
            End If
        End Get

    End Property

End Class

But then I basically found out that you can't override a protected member with a public one. I've had very little experience with creating new classes etc, so I'm stumped.

So if anyone can tell me how to go about checking the darned checkbox, I'd be eternally grateful! I've spent a full working day trying to solve the problem, but with no luck!

Thanks in advance!

+1  A: 

For static controls, the view state of controls is restored in Page_Init, which happens before Page_Load, so they contain the correct values in Page_Load. Dynamic controls are created in Page_Load, so their viewstate is incorrect in Page_Load and will be restored after Page_Load, but before calling event handlers. MSDN says:

After the Page_Load event has run, but before control event-handling methods are called, the remaining view state information is loaded into the dynamically created controls.

This is why Checked returns false, and why changing the visibility of CheckBox.ViewState will not solve your problem.

Solution (untested, but I think it should work): Create all controls (even those that you don't want to display) in Page_Load. Attach an event handler on CheckedChanged to your CheckBoxes (in Page_Load). After Page_Load has finished, ASP.NET will restore the view state of the newly created controls (that's why it is important to create the same controls in Page_Load, so that ASP.NET can correctly map the view state to the control), and ASP.NET will call your event handler for those CheckBoxes that have been changed. There, you can remove the rows you don't want to display.


This is how you add the event handler

AddHandler objCheckbox.CheckedChanged, AddressOf MyCheckedChangedFunction

This function would look something like this:

Function MyCheckedChangedFunction(sender As Object, e As EventArgs)
    Dim objCheckbox = DirectCast(sender, CheckBox)

    ... access objCheckbox.Changed and do something useful here ...
End Function
Heinzi
Hi, thanks for your reply.I did as you suggested, and added an event handler to the checkboxes as they were being created in Page_Load. I used the following code: objCheckbox.OnCheckedChanged = "MyFunction"But I get the following error:**'System.Web.UI.WebControls.CheckBox.Protected Overridable Sub OnCheckedChanged(e As System.EventArgs)' is not accessible in this context because it is 'Protected'.**Do you know what might cause this error? As I mentioned previously, when I encountered this error before I couldn't override the function to make it public.Thanks.
Dom
I updated my answer. For adding an event handler, you need to access `CheckedChanged` (without the `On`)... sorry, if my answer was misleading in this regard. I've added some example clode.
Heinzi
Hi, thanks for the comments! Although when I use **CheckedChanged** I get the following error **'Public Event CheckedChanged(sender As Object, e As System.EventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.** But it's OK, I've managed to sort the problem. I check the state of the checkbox during **Page_PreRender** (which works) and remove any rows from the form at that point. Thanks for your replies though!
Dom
Ah, I forgot that your are using VB.NET, you have to use AddHandler there (updated my answer). Glad to hear that you solved it; PreRender sounds like a good idea.
Heinzi