I create a readonly textbox dynamically on page load/init and on the first load (not IsPostBack) I set the text. I also have a button on the page with a click event that changes the content of the textbox. Using another button, I read the text of the textbox. The problem is as follows:
If I click the button that changes the textbox and then click the button that reads the text of the textbox, it gets it fine.
If I just load the page and click the button that reads the text of the textbox, it brings back an empty string
I need both scenarios to bring back a result - whether it's the original text or the new programmatically changed text.
Example code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim Textbox As New TextBox()
Textbox.ID = "Bob"
Textbox.ReadOnly = True
If Not IsPostBack Then
Textbox.Text = "Initial Text"
End If
Content.Controls.Add(Textbox)
Dim Button As New Button()
Button.Text = "Change text"
AddHandler Button.Click, AddressOf Button_Click
Content.Controls.Add(Button)
End Sub
Protected Sub Button_Click(ByVal sender As Object, ByVal e As EventArgs)
'FindControlRecursive is locally defined - just finds a control based on root control and ID
CType(FindControlRecursive(Content, "Bob"), TextBox).Text = "Hmmmmm"
End Sub
Private Sub Submit_Click(sender As Object, e As EventArgs) Handles Submit.Click
Dim Textbox As TextBox = CType(FindControlRecursive(Content, "Bob"), TextBox)
MsgBox(Textbox.Text)
End Sub
I could just reinitialise the textbox each time but this is just an example and in practice I'll be pulling it from SQL and if I have several read only controls on the page I'd rather get the control to persist its text rather than going back to SQL each time.
I found two ways to solve this, the second being the more favoured approach (depending on situation):
Specifically add the initial text to the viewstate and then set the text on each postback using the value from viewstate:
If Not IsPostBack Then
Textbox.Text = "Initial Text"
ViewState("Bob") = Textbox.Text
Else
Textbox.Text = ViewState("Bob")
End If
Add a PreRender event to the textbox that just sets it text to itself. This takes place after the ViewState starts being tracked so it's added to the viewstate via the control and is persisted across postbacks:
If Not IsPostBack Then
Textbox.Text = "Initial Text"
AddHandler Textbox.PreRender, AddressOf PersistPastInitialLoad
End If
And add new sub:
Protected Sub PersistPastInitialLoad(ByVal sender As Object, ByVal e As EventArgs)
'This is just for example - would need refining for different types of controls
CType(sender, TextBox).Text = CType(sender, TextBox).Text
End Sub
Essentially they both do the same thing - hold the text in viewstate - but it depends on implementation which is the best to use. The first implementation might be a bit easier to read/work with but it would result in redundant viewstate bloat if you click the button to change the textbox text (i.e. you'll have the initial text in viewstate against the viewstate key you created as well as the current text added to viewstate by the control onchange).