Maintain State Using LoadControl()

Hi,

I'm new to using templated controls and I'm developing an in-house Asp.Net application to provide "maintenance" type tools for our developers.  I have made each tool a User Control.  On the main page, I have a menu (made up of link buttons) listing each tool.  When the user clicks on a button to select a tool, I am using the LoadControl() method to load the User Control into the content area (a panel server control).  The control loads fine, but the problem is, the User Control has multiple buttons, pageable datagrids, etc. to perform their tasks.  When anything in the User Control causes a postback, the entire control disappears.  The panel control EnableViewState property is set to true.  Any ideas?  Here is a generic portion of some of the code:

Menu.aspx:

<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Menu.aspx.vb" Inherits="AdminTools.Menu"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
      <HEAD>
            <title>Programmer's Admin Tools</title>
            <meta content="Microsoft Visual Studio.NET 7.0" name="GENERATOR">
            <meta content="Visual Basic 7.0" name="CODE_LANGUAGE">
            <meta content="JavaScript" name="vs_defaultClientScript">
            <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
            <LINK href="Styles.css" type="text/css" rel="stylesheet">
      </HEAD>
      <body>
            <form id="Form1" method="post" runat="server">
                  <TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
                        <TR>
                              <TD vAlign="bottom" noWrap>
                                    <H2>Programmer's Admin Tools</H2>
                              </TD>
                        </TR>
                        <TR>
                              <TD>
                                    <TABLE id="Table2" cellSpacing="1" cellPadding="1" width="100%" border="0">
                                          <TR>
                                                <TD vAlign="top" width="190">
                                                      <H5>MENU</H5>
                                                      <P><asp:linkbutton id="cmdSetSystemSecurity" runat="server">Set Security for Internal System</asp:linkbutton><br>
                                                            <asp:LinkButton id="cmdPersonManagement" runat="server">Manage Person Master Database</asp:LinkButton></P>
                                                </TD>
                                                <TD vAlign="top" width="10"></TD>
                                                <TD vAlign="top">
                                                      <asp:Panel id="pnlControlHolder" runat="server"></asp:Panel></TD>
                                          </TR>
                                    </TABLE>
                              </TD>
                        </TR>
                  </TABLE>
            </form>
      </body>
</HTML>

Menu.aspx.vb:

Public Class Menu
    Inherits System.Web.UI.Page
    Protected WithEvents cmdSetSystemSecurity As System.Web.UI.WebControls.LinkButton
    Protected WithEvents pnlControlHolder As System.Web.UI.WebControls.Panel
    Protected WithEvents cmdPersonManagement As System.Web.UI.WebControls.LinkButton

#Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
    End Sub

#End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
    End Sub

    Private Sub cmdSetSystemSecurity_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetSystemSecurity.Click
        Dim mySecurityControl As SetSecurityForSystem = LoadControl("SetSecurityForSystem.ascx")
        pnlControlHolder.Controls.Add(mySecurityControl)
    End Sub
End Class

SetSecurityForSystem.ascx:

<%@ Control Language="vb" AutoEventWireup="false" Codebehind="SetSecurityForSystem.ascx.vb" Inherits="AdminTools.SetSecurityForSystem" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
      <TR>
            <TD vAlign="top" align="right">System Name:</TD>
            <TD>
                  <asp:TextBox id="txtSystemName" runat="server" MaxLength="50" Columns="30"></asp:TextBox></TD>
      </TR>
      <TR>
            <TD vAlign="top" align="right">Authorized Users:</TD>
            <TD>
                  <asp:ListBox id="lstUsers" runat="server" Rows="20" SelectionMode="Multiple"></asp:ListBox></TD>
      </TR>
      <TR>
            <TD></TD>
            <TD>
                  <asp:Button id="cmdSetSecurity" runat="server" Text="Set Security"></asp:Button></TD>
      </TR>
      <TR>
            <TD></TD>
            <TD></TD>
      </TR>
</TABLE>

SetSecurityForSystem.ascx.vb:

Imports Microsoft.ApplicationBlocks.Data

Public MustInherit Class SetSecurityForSystem
    Inherits System.Web.UI.UserControl
    Protected WithEvents txtSystemName As System.Web.UI.WebControls.TextBox
    Protected WithEvents lstUsers As System.Web.UI.WebControls.ListBox
    Protected WithEvents cmdSetSecurity As System.Web.UI.WebControls.Button

#Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
    End Sub

#End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
        lstUsers.DataSource = SqlHelper.ExecuteReader(ConfigurationSettings.AppSettings("ConnectionString"), CommandType.Text, "SELECT personid, RTRIM(username) + ' (' + RTRIM(userid_short) + ')' As Name FROM companyperson")
        lstUsers.DataTextField = "Name"
        lstUsers.DataValueField = "personid"
        lstUsers.DataBind()
    End Sub

End Class

Thanks in advance for the help.
LVL 4
DJDougAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

reavesCommented:
When you are creating dynamic controls in a container, you have to recreate each control with every postback. It seems weird, I know, because after you recreate the dynamic control it's propertires and values will still be restored by viewstate. You just have to alert your page that these controls still exist since you are not doing it declaratively.

So:

Add this Property:

'This property will keep track of how many control we have on the page
Private Property ControlCount() As Integer
  Set(ByVal Value As Integer)
    ViewState("ControlCount") = Value
  End Set
  Get
    If ViewState("ControlCount") Is Nothing Then
      ViewState("ControlCount") = 0
    End If
    Return ViewState("ControlCount")
  End Get
End Property


Add this sub:

'This sub will call laodcontrol and add the control to the page
Private Sub CreateControl(ByVal intIndex As Integer)
  Dim mySecurityControl As SetSecurityForSystem = LoadControl("SetSecurityForSystem.ascx")
  pnlControlHolder.Controls.Add(mySecurityControl)
  mySecurityControl.ID = "mySecurityControl" & intIndex
End Sub


Change your click event handler to this:

   'Add a new control and increment our counter when the button is clicked
   Private Sub cmdSetSystemSecurity_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetSystemSecurity.Click
     CreateControl(ControlCount)
     ControlCount += 1
   End Sub

Change your Page_Load to this:

   'If the page is posted back, check our counter and re add teh appropriate number of controls
   Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Dim intIndex As Integer = 0
      If Page.IsPostback()
        For intIndex = 0 To ControlCount - 1
          CreateControl(intIndex)
        Next
      End If
   End Sub



So if you filter that for typos :) and re add the dynamic controls each time the page posts back, then you will they will reappear WITH their pre postback properties.

--
Ryan Eaves
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
DJDougAuthor Commented:
Works like a charm (with no typos... :) !).  Thanks for the superfast response...AWESOME!  Appreciate it.  Take care.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.