Search code examples
asp.netvb.netpostbackviewstate

Stuck on Dynamic Controls, Viewstate, and Postback. Simplified example


I've been reading posts and links, and articles about viewstate, and statebag, and postback and page creation.

I'm a pretty decent amateur, but this one just isn't sinking in, could someone show me an example of how this might be done?

OK, here is what I am trying to do with this example

Create a table where the left column has LinkButtons

When each linkButton is clicked it opens a bunch of Imagebuttons in the right column

Each Imagebutton then pops up a message

The problem is the imagebutton does not trigger the message

here is the front end:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="simple.aspx.vb" Inherits="simple" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>simple</title>
</head>
<body>
<form id="form1" runat="server">

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

<asp:Table id="MainTable" runat="server">
<asp:TableRow>

<asp:TableCell ID ="cell1" BackColor="LightBlue" />

<asp:TableCell ID ="cell2" BackColor="LightBlue" />

</asp:TableRow>
</asp:Table>

</form>
</body>
</html>

and here is the code:

Partial Class simple
Inherits System.Web.UI.Page

Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init

    Dim NewTableButton As LinkButton = New LinkButton
    NewTableButton.Text = "Text Created from 1st SQL Query"
    AddHandler NewTableButton.Click, AddressOf LoadContacts

    cell1.Controls.Add(NewTableButton)

End Sub

Protected Sub LoadContacts(sender As Object, e As System.EventArgs)

    Dim TextPassedfromLinkButton As String = sender.text.ToString

    Dim imgGear As New ImageButton
    imgGear.ImageUrl = "../graphics/gear.jpg"
    imgGear.AlternateText = "Text Created from 2nd SQL Query using the " _
 & TextPassedfromLinkButton & " as a query parameter"
    AddHandler imgGear.Click, AddressOf message

    cell2.Controls.Add(imgGear)

End Sub

Protected Sub message(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim strText As String = sender.text.ToString
    Dim alertString As String = "alert('" & strText & "');"
    ScriptManager.RegisterStartupScript(Me, [GetType](), "showalert", alertString, True)

End Sub

End Class

Here is the view source after you click the button that should popup the message

 <table id="MainTable">
 <tr>
 <td id="cell1" style="background-color:LightBlue;"><a href="javascript:__doPostBack(&#39;ctl03&#39;,&#39;&#39;)">Text Created from 1st SQL Query</a></td>
 <td id="cell2" style="background-color:LightBlue;"><input type="image" name="ctl04" src="../graphics/gear.jpg" alt="Text Created from 2nd SQL Query using the Text Created from 1st SQL Query as a query parameter" /></td>
 </tr>
 </table>

So in the meantime I got this to work (updated 10:49 est)

Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init

    Dim NewTableButton As LinkButton = New LinkButton
    NewTableButton.Text = "Text Created from 1st SQL Query"
    'AddHandler NewTableButton.Click, AddressOf LoadContacts
    AddHandler NewTableButton.Click, Function() LoadContacts(NewTableButton.Text)

    cell1.Controls.Add(NewTableButton)

    If IsPostBack Then
        LoadContacts(NewTableButton.Text)
    End If

End Sub

Private Function LoadContacts(strText As String) As Integer

    Dim TextPassedfromLinkButton As String = strText

    Dim imgGear As New ImageButton
    imgGear.ID = "uniquename"
    EnableViewState = False
    imgGear.ImageUrl = "../graphics/gear.jpg"
    imgGear.AlternateText = "Text Created from 2nd SQL Query using the " & TextPassedfromLinkButton & " as a query parameter"
    AddHandler imgGear.Click, AddressOf message

    cell2.Controls.Add(imgGear)

    Return 0

End Function

The only problem is I get 2 Identical imgGears

duplicate buttons http://reinsmith.net/graphics/simple1.png message displayed http://reinsmith.net/graphics/simple2.png


Solution

  • The problem here is you are instantiating the imgGear button during the event handler of another button.

    It seems totally logical to do so, but the event handler for imgGear will never be triggered if imgGear is created and added to the control tree too late in the page lifecycle, e.g. in an event handler or during OnPreRender.

    It is very hard to achieve what you are trying to do using standard .Net practices...I have never managed it. You may also notice a text box added during an event handler doesn't usually retain its value on postback, again because it has been added too late in the page lifecycle.

    You really need to detect the context during OnInit or CreateChildControls, because a button instantiated and added to the control tree during that phase will have its handler triggered.

    I have developed a work around though...and like most work arounds it's not pretty...but it can get you out of a tight spot:

    During OnInit you can tell if your button caused the postback, if it's a member variable. Intialise the NewTableButton in the contructor...then you can detect if it was clicked during OnInit...

       Private NewTableButton as Button
    
       Public Sub New()
            MyBase.New()
            NewTableButton = New LinkButton
            NewTableButton.Text = "Text Created from 1st SQL Query"
        End Sub
    
        Protected Overrides Sub OnInit(e As EventArgs)
            MyBase.OnInit(e)
            cell1.Controls.Add(NewTableButton)
            If Not IsNothing(Page.Request(NewTableButton.UniqueID)) Then
               ' Create and add imgGear Button
               LoadContacts
            End If
        End Sub
    

    However, the text box / drop down values are not available during OnInit using standard practices...so, you may have to a) Defer the reading of them until OnPreRender, or b) Use the Page.Request(Control.UniqueID) to read the value of input controls during OnInit.

    This is one of the biggest issues I have with .Net web development, it causes headaches and I don't like work arounds...

    I love to know if there was an alternative to this workaround, but It's the only way I've found to achieve what you're trying to achieve.