Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamic Controls - how to replace after their events fire

5 views
Skip to first unread message

Brad

unread,
Oct 11, 2002, 1:42:15 PM10/11/02
to
Question: How to I replace/alter the contents of a dynamic control after a
postback event for the same dynamic control I want to replace/alter?

Here's what I'm doing: I am dynamically creating a large table with quite
a few embedded controls. I've added eventhandlers for the dynamic controls
and the events all fire correctly because I've recreated the table and
controls on postback. So far, so good......
Now, the result of the events in the dynamic table controls are to re-create
the same table and controls that are raising the events. If I "re-create"
the table in the postback events I get another instance of my table (now I
have two tables on the page). I've done a response.redirect to the page
which gives me the correct result...but this seems inefficient.

So back to my question and the paradox: On a postback, how would I replace
the table (or any other control) which I had to recreate on the postback in
order to have the events fire.

I'm using VB.NET and I've create my table and controls all within a web user
control.

Thanks

Brad

Mike Moore [MS]

unread,
Oct 14, 2002, 3:28:44 PM10/14/02
to
Hi Brad,

I don't understand your comment about having add the controls in a post
back. Here's a sample in which the dynamically added controls are added
from the first browsing of the page.

Protected WithEvents TextBox1 As System.Web.UI.WebControls.TextBox
Protected WithEvents Button1 As System.Web.UI.WebControls.Button

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
TextBox1 = New TextBox()
Button1 = New Button()
Me.Controls(1).Controls.Add(TextBox1)
Me.Controls(1).Controls.Add(Button1)
End Sub

Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles TextBox1.TextChanged
Response.Write(TextBox1.Text)
End Sub

Private Sub Button1_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Button1.Click
Button1.Text = TextBox1.Text
End Sub

Can you post a sample which demonstrates what you are doing?
If you can, create a sample with just one or two controls and no table or
user control. If that's too simplistic to demonstrate the behavior, try to
create a sample that's as simple as possible that does demonstrate the
behavior.

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>Reply-To: "Brad" <nos...@co.lane.or.us>
>From: "Brad" <nos...@co.lane.or.us>
>Subject: Dynamic Controls - how to replace after their events fire
>Date: Fri, 11 Oct 2002 10:42:15 -0700
>Lines: 28
>X-Priority: 3
>X-MSMail-Priority: Normal
>X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
>X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
>Message-ID: <eKR#e1UcCHA.2052@tkmsftngp12>
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>NNTP-Posting-Host: 199.79.46.126
>Path: cpmsftngxa08!tkmsftngp01!tkmsftngp12
>Xref: cpmsftngxa08
microsoft.public.dotnet.framework.aspnet.webcontrols:6318
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Brad

unread,
Oct 14, 2002, 6:02:25 PM10/14/02
to
Thanks for your reply, Mike.
Okay, let's see if I can do a better job of explaining this. Below is an
simplified example of my web user control (I've verified that this sample
will work..or more exactly..it reproduces my issues here). This control
will render a table which displays a weekly calendar. There are two link
buttons within my rendered table "<<" Previous Week and Next Week ">>".
Clicking on "<<" or ">>" will raise the "Change" event which moves the
calendar back or forward a week. All this works, the table is rendered and
the event does fire, but........

Here's where I hope I remain clear....
**IF** I understand correctly, .Net has to re-render the table and it's
controls on the post back before any events fire for controls that were
rendered within the table. So, the re-rendering takes place *before* my
Change event is fired. My expected result is that the Change event will
move the calendar forward/back a week, to the week currently stored in the
session variable "eventdate".
(1) If I do nothing, the page does move forward/back but it is always one
week out of sync with the expected date. This out of sync makes sense as
the controls were re-rendered before the event is fired that updates the
session variable "eventdate".
(2) If I use a response.redirect back to the same page everything work fine
because the first instance of the page updates the date and redirects to
itself, where the page/control is drawn with the updated date.
(3) If attempt to re-render the table and controls in the Change event I
two instances of the table drawn on the page #1 prior to the event being
fired and #2 after the event was fired.


In conclusion, using (2) the redirect, gives me the result I expected and I
could keep quite and go away.......but I was wondering if there was a better
way to do this...without having to do a redirect?

Thanks

Brad

'********************************************************
' Start of my example. This entire code sample can be cut/pasted into a
user web control
' (there may be some word wraps from any email formatting)
'********************************************************
Public MustInherit Class MyControl
Inherits System.Web.UI.UserControl

#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.
BuildDisplay()
InitializeComponent()
End Sub

#End Region


Private Property EventDate() As Date
Get
If Not (IsNothing(Session("eventdate"))) Then
Return Session("eventdate")
Else
Return Today
End If

End Get
Set(ByVal Value As Date)
Session("eventdate") = Value
End Set
End Property

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

End Sub

Private Function BuildDisplay()
Dim tblWeek As New Table()
Dim tblr As TableRow
Dim tblc As TableCell
Dim intHour As Integer
Dim intDay As Integer

Dim dteDisplay As Date

If EventDate.DayOfWeek <> DayOfWeek.Sunday Then
dteDisplay = DateAdd(DateInterval.Day, EventDate.DayOfWeek * -1,
EventDate)
End If

With tblWeek
.ID = "tblWeek"
.Width = New Unit(100, UnitType.Percentage)
.CellPadding = 0
.CellSpacing = 0
.BorderStyle = BorderStyle.Solid
.BorderWidth = New Unit(1, UnitType.Pixel)
End With

'********************************************
' Build Title
'********************************************
tblr = New TableRow()
With tblr
tblc = New TableCell()
Dim lbtn As New LinkButton()
lbtn.CommandName = DateInterval.Day
lbtn.CommandArgument = -7
lbtn.Text = "&LT;&LT;"
lbtn.ToolTip = "Previous Week"
AddHandler lbtn.Click, AddressOf Me.Change
tblc.Controls.Add(lbtn)
tblr.Cells.Add(tblc)
End With

With tblr
tblc = New TableCell()
tblc.Text = "Week of " & Format(dteDisplay, "MMMM d, yyyy")
tblc.ColumnSpan = 7
tblr.Cells.Add(tblc)
End With

With tblr
tblc = New TableCell()
Dim lbtn As New LinkButton()
lbtn.CommandName = DateInterval.Day
lbtn.CommandArgument = 7
lbtn.text = "&GT;&GT"
lbtn.ToolTip = "Next Week"
AddHandler lbtn.Click, AddressOf Me.Change
tblc.Controls.Add(lbtn)
tblr.Cells.Add(tblc)
End With
tblWeek.Rows.Add(tblr)
'********************************************
' Build Day Titles
'********************************************

tblr = New TableRow()
With tblr
tblc = New TableCell()
tblc.Wrap = False
.Cells.Add(tblc)
End With

Dim dteTitle As Date = dteDisplay
For intDay = DayOfWeek.Sunday To DayOfWeek.Saturday
tblc = New TableCell()
tblc.Text = Format(dteTitle, "ddd, MMM d")
tblc.BorderStyle = BorderStyle.Solid
tblc.BorderWidth = New Unit(1, UnitType.Pixel)
tblr.Cells.Add(tblc)
dteTitle = DateAdd(DateInterval.Day, 1, dteTitle)
Next

With tblr
tblc = New TableCell()
tblc.Wrap = False
.Cells.Add(tblc)
End With
tblWeek.Rows.Add(tblr)


'********************************************
' Build Time and Days
'********************************************

For intHour = 7 To 19
tblr = New TableRow()
Dim strTime As String = Format(DateAdd(DateInterval.Hour,
intHour, Today()), "hh:mm tt")
With tblr
tblc = New TableCell()
tblc.Wrap = False
tblc.Text = strTime
tblc.BorderStyle = BorderStyle.Solid
tblc.BorderWidth = New Unit(1, UnitType.Pixel)
.Cells.Add(tblc)
End With
For intDay = 0 To 6
tblc = New TableCell()
With tblc
.Text = ""
tblc.BorderStyle = BorderStyle.Solid
tblc.BorderWidth = New Unit(1, UnitType.Pixel)
End With
tblr.Cells.Add(tblc)
Next
With tblr
tblc = New TableCell()
tblc.Wrap = False
tblc.Text = strTime
tblc.BorderStyle = BorderStyle.Solid
tblc.BorderWidth = New Unit(1, UnitType.Pixel)
.Cells.Add(tblc)
End With

tblWeek.Rows.Add(tblr)
Next

Me.Controls.Add(tblWeek)

End Function

Private Sub Change(ByVal sender As System.Object, ByVal e As EventArgs)
EventDate = DateAdd(CType(sender.commandname, DateInterval),
CType(sender.commandargument, Double), EventDate)
Response.Write(EventDate)

' Uncommenting this next line will render a calendar of the correct
week
' however there will be two calendars drawn on the page
'************************
' BuildDisplay()
'
'************************
'Uncommenting this line instead will display the expected
results...because is causes a new page to be
' rendered...and it's using the revised EventDate session
parameter. Note the "" as this expects
' to be used in a page names "default.aspx"
' Response.Redirect("")
End Sub

End Class

'********************************************************
' End of my example
'********************************************************

""Mike Moore [MS]"" <mic...@online.microsoft.com> wrote in message
news:xYJN8e7cCHA.1904@cpmsftngxa06...

Mike Moore [MS]

unread,
Oct 14, 2002, 10:36:24 PM10/14/02
to
Hi Brad,

I agree, this is a self-defeating situation. .NET won't fire the control's
change event unless a change has occurred on the control. This requires
that you create the control first, before .NET examines whether a change
has occurred. If you don't create the control until later, then .NET won't
recognize the change and won't fire the change event.

Meanwhile, the creation of your control is dependant on the results of the
change event. So, creation of the control must take place before the change
event in order for the change event to fire. Also, the control must be
created after the change event because the results of the change event are
required in order to display the control with the new data.

I've tried several experiments and haven't found a resolution yet. I expect
to have more for you tomorrow.

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>Reply-To: "Brad" <nos...@co.lane.or.us>
>From: "Brad" <nos...@co.lane.or.us>

>References: <eKR#e1UcCHA.2052@tkmsftngp12> <xYJN8e7cCHA.1904@cpmsftngxa06>
>Subject: Re: Dynamic Controls - how to replace after their events fire
>Date: Mon, 14 Oct 2002 15:02:25 -0700
>Lines: 341


>X-Priority: 3
>X-MSMail-Priority: Normal
>X-Newsreader: Microsoft Outlook Express 6.00.2600.0000
>X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000

>Message-ID: <OrvI208cCHA.1652@tkmsftngp09>
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>NNTP-Posting-Host: 199.79.46.126
>Path: cpmsftngxa06!tkmsftngp01!tkmsftngp09
>Xref: cpmsftngxa06
microsoft.public.dotnet.framework.aspnet.webcontrols:6327
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Kim Bach Petersen

unread,
Oct 15, 2002, 6:33:54 AM10/15/02
to
> In conclusion, using (2) the redirect, gives me the result I
> expected and I could keep quite and go away.......but I was wondering
> if there was a better way to do this...without having to do a
> redirect?

I have also used redirect succesfully, but depending on the control, there
might be a better option that just rebinding the data and do a redirect:
re-instancing the control. Given that the Page_Render-event comes after
control events, the control eventhandler can add or remove new controls.
Thus you might want to make you calender as composite control itself, making
you able to remove and re-instancing it easily.

An example:

Public Class ModulLogout : Inherits Control : Implements INamingContainer
Protected Overrides Sub CreateChildControls()
Dim LogoutButton As New LinkButton
LogoutButton.Text = "Logout"
LogoutButton.Id = "Logout"
LogoutButton.CommandName = "Logout"
AddHandler LogoutButton.Command, AddressOf Logout
Me.Controls.Add(LogoutButton)
End Sub
Private Sub Logout(sender As Object, e As CommandEventArgs)
FormsAuthentication.SignOut()
Me.Controls.Clear
Me.Controls.Add(New LiteralControl("<p>Logged out!</p>")
End Sub

Kim :o)


Mike Moore [MS]

unread,
Oct 15, 2002, 2:25:32 PM10/15/02
to
Hi Brad and Kim,

My solution is a variation on Kim's. I don't clear all the controls, just
the one we're concerned about. I found that I had to make the removal a
recursive function to get all nested child controls.

Here's the previous code sample with a new function added to remove the old
control before re-adding it in the change event.


'********************************************************
' Start of my example. This entire code sample can be cut/pasted into a
user web control
' (there may be some word wraps from any email formatting)
'********************************************************

Imports System.Reflection

Public MustInherit Class MyControl
Inherits System.Web.UI.UserControl

Dim tblWeek As Table

#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()
BuildDisplay()
End Sub

#End Region

Private Property EventDate() As Date
Get
If Not (IsNothing(Session("eventdate"))) Then
Return Session("eventdate")
Else
Return Today
End If

End Get
Set(ByVal Value As Date)
Session("eventdate") = Value
End Set
End Property

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
End Sub

Private Function BuildDisplay()


Dim tblr As TableRow
Dim tblc As TableCell
Dim intHour As Integer
Dim intDay As Integer
Dim dteDisplay As Date

Response.Write(EventDate)

tblWeek = New Table()


If EventDate.DayOfWeek <> DayOfWeek.Sunday Then
dteDisplay = DateAdd(DateInterval.Day, EventDate.DayOfWeek *
-1, EventDate)
End If

With tblWeek
.ID = "tblWeek"
.Width = New Unit(100, UnitType.Percentage)
.CellPadding = 0
.CellSpacing = 0
.BorderStyle = BorderStyle.Solid
.BorderWidth = New Unit(1, UnitType.Pixel)
End With

'********************************************
' Build Title
'********************************************
tblr = New TableRow()
With tblr
tblc = New TableCell()
Dim lbtn As New LinkButton()
lbtn.CommandName = DateInterval.Day
lbtn.CommandArgument = -7
lbtn.Text = "&LT;&LT;"
lbtn.ToolTip = "Previous Week"

lbtn.ID = "LEFT"


AddHandler lbtn.Click, AddressOf Me.Change
tblc.Controls.Add(lbtn)
tblr.Cells.Add(tblc)
End With

With tblr
tblc = New TableCell()
tblc.Text = "Week of " & Format(dteDisplay, "MMMM d, yyyy")
tblc.ColumnSpan = 7
tblr.Cells.Add(tblc)
End With

With tblr
tblc = New TableCell()
Dim lbtn As New LinkButton()
lbtn.CommandName = DateInterval.Day
lbtn.CommandArgument = 7

lbtn.Text = "&GT;&GT"
lbtn.ToolTip = "Next Week"
lbtn.ID = "RIGHT"

tblWeek.Rows.Add(tblr)
Next

Me.Controls.Add(tblWeek)

End Function

'Remove the existing control including children
'Start from the top level container
RemoveAll(Me)
'Re-add the control, including children
BuildDisplay()
End Sub

'*******************************************************************
'SUB RemoveAll - parameter Control
'Remove all existing controls from the specified control.
'Start from the end of the control collection
'to avoid index out of range errors
'cannot do this with a for each loop, becuase that would modify
'the collection that the enumerator is bound to, which is an error.
'*******************************************************************
Public Sub RemoveAll(ByRef container As Control)
Dim ctl As Control
Dim x As Integer
For x = container.Controls.Count - 1 To 0 Step -1
ctl = container.Controls(x)
If ctl.HasControls Then
'do a recursive remove, we are removing the controls in the
container
'before removing the container
RemoveAll(ctl)
End If
container.Controls.Remove(ctl)
Next
End Sub
End Class


Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>From: "Kim Bach Petersen" <msn...@kensho.dk>
>References: <eKR#e1UcCHA.2052@tkmsftngp12> <xYJN8e7cCHA.1904@cpmsftngxa06>
<OrvI208cCHA.1652@tkmsftngp09>
>Subject: Re: Dynamic Controls - how to replace after their events fire
>Date: Tue, 15 Oct 2002 12:33:54 +0200
>Lines: 32
>X-Priority: 3
>X-MSMail-Priority: Normal
>X-Newsreader: Microsoft Outlook Express 6.00.2720.3000


>X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000

>Message-ID: <OzFYyYDdCHA.392@tkmsftngp09>
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>NNTP-Posting-Host: 80.198.43.82
>Path: cpmsftngxa08!tkmsftngp01!tkmsftngp09
>Xref: cpmsftngxa08
microsoft.public.dotnet.framework.aspnet.webcontrols:6386
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Brad

unread,
Oct 15, 2002, 8:00:44 PM10/15/02
to
Cool! Thanks, Mike, that works great. A note to others who may read
this. Make sure you set the ID of the controls you are dynamically creating
or this RemoveAll will not work. You did that in your example, Mike, but I
didn't at first when incorporating into my actual code (setting the id in
the lbtn controls in your example) and the code did not work properly.
Makes sense why and once I set the ID's the code worked great.

Thanks again!

Brad

P.S. Kim, I thought about a custom control but the actual control and the
integration with other objects in the web project didn't make sense to put
the time into a control (but that could change).

""Mike Moore [MS]"" <mic...@online.microsoft.com> wrote in message

news:yKXbcgHdCHA.2320@cpmsftngxa06...

Kim Bach Petersen

unread,
Oct 16, 2002, 2:19:52 PM10/16/02
to
> P.S. Kim, I thought about a custom control but the actual control
> and the integration with other objects in the web project didn't make
> sense to put the time into a control (but that could change).

In this context, making a custom controls is not necessary but still very
convinient.

It will enable you to add or remove more meaningfull collections of
controls: Removing the customcontrol will clear all childcontrols as well,
re-instancing will add it all in one single process - without needing loops
or recursions to search for the controls in question.

Kim :o)

--
Put an end to Outlook Express's messy quotes with this automated fix!
· http://flash.to/oe-quotefix/ ·


Brian Chapman

unread,
Oct 23, 2002, 3:05:06 PM10/23/02
to
Can anyone tell me how the ViewState was set in the code example
above? (the working example)

Brian

"Kim Bach Petersen" <msn...@kensho.dk> wrote in message news:<uELG0BUdCHA.2248@tkmsftngp11>...

Mike Moore [MS]

unread,
Oct 23, 2002, 8:40:12 PM10/23/02
to
Hi Brian,

The original question was how to modify a dynamically created control
without disabling server events associated with the control. The sample
code demonstrated one way to do this. The sample does not address
ViewState. So, you asked how the sample sets ViewState. The answer is that
none of the code in the sample addresses ViewState.

Does that answer your question?

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>From: ripcu...@yahoo.com (Brian Chapman)
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols


>Subject: Re: Dynamic Controls - how to replace after their events fire

>Date: 23 Oct 2002 12:05:06 -0700
>Organization: http://groups.google.com/
>Lines: 19
>Message-ID: <2ea64ade.02102...@posting.google.com>
>References: <eKR#e1UcCHA.2052@tkmsftngp12> <xYJN8e7cCHA.1904@cpmsftngxa06>
<OrvI208cCHA.1652@tkmsftngp09> <OzFYyYDdCHA.392@tkmsftngp09>
<yKXbcgHdCHA.2320@cpmsftngxa06> <uRpinbKdCHA.1004@tkmsftngp08>
<uELG0BUdCHA.2248@tkmsftngp11>
>NNTP-Posting-Host: 63.109.229.13
>Content-Type: text/plain; charset=ISO-8859-1
>Content-Transfer-Encoding: 8bit
>X-Trace: posting.google.com 1035399906 9335 127.0.0.1 (23 Oct 2002
19:05:06 GMT)
>X-Complaints-To: groups...@google.com
>NNTP-Posting-Date: 23 Oct 2002 19:05:06 GMT
>Path:
cpmsftngxa08!tkmsftngp01!newsfeed00.sul.t-online.de!t-online.de!newsfeed.fre
enet.de!newsfeed.news2me.com!newsfeed-west.nntpserver.com!hub1.meganetnews.c
om!nntpserver.com!telocity-west!TELOCITY!sn-xit-03!sn-xit-01!sn-xit-04!super
news.com!postnews1.google.com!not-for-mail


>Xref: cpmsftngxa08
microsoft.public.dotnet.framework.aspnet.webcontrols:6629
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols
>

Brian Chapman

unread,
Oct 26, 2002, 12:11:12 PM10/26/02
to
Yes. However, maybe I should tell you my problem...

I have a page with one user control (user control added at design
time). The user control consists of a panel added at design time and
a bunch of linkbuttons added dynamically in either the page_load or in
the event handler when one of the existing linkbuttons is clicked.
(this is supposed to turn out like a tree view for browsing categories
in a catalog - we're using commerce server 2002.)

when the page is hit the first time, the "root categories" are loaded
into linkbuttons in page_load (using a helper method) and the command
events are registered for those buttons.

when a button is clicked the page re-loads (the buttons are added
again in page_load) and then the event fires. the event handler
causes the buttons to be loaded again and a second level of buttons
(sub-categories) is loaded below the button that was clicked (if it
has any sub-categories) in a recursive fashion.

this pattern should theoretically accomodiate n levels of hierarchy.

the problem (one of them) is that it takes 2 clicks on each link
button for the event to actually be fired (with the exception of the
first time the pages loads).

viewstate is disabled. it doesn't seem to matter where i load the
buttons (page_init, page_load, etc) because i get the same result. i
thought i understood the page processing stages, but i have a feeling
that's where i'm missing out!

can you describe how a tree view control could be built using this
type of method or tell me where i might be going wrong? i'll try to
put some code together to show what is happening.

thanks in advance. Brian

mic...@online.microsoft.com ("Mike Moore [MS]") wrote in message news:<dxSM9WveCHA.2280@cpmsftngxa08>...

Mike Moore [MS]

unread,
Oct 28, 2002, 3:13:46 PM10/28/02
to
Hi Brian,

QUESTION
In either the page init or load, I dynamically add some controls which have
events. Also, in the control events, I sometimes add yet additional
controls. The problem is that all the additional controls have to be
clicked twice in order to get their events to fire.

ANSWER
I may need to see the code sample you said you are working on to give you a
solution. Here's my first idea.

In order for ASP.NET to fire an event for a dynamically added control, that
control needs to be re-added during either init or load (preferably init).
I think you need to keep track of which controls you are adding in your
control events so that you can re-add them in the init event with each
subsequent execution of the page. Session variables might be a good place
for this. With session variables, just put some data (like text) into the
session variables and then use that data in the init function to recreate
the controls.

HTH.

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>From: ripcu...@yahoo.com (Brian Chapman)
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>Subject: Re: Dynamic Controls - how to replace after their events fire

>Date: 26 Oct 2002 09:11:12 -0700
>Organization: http://groups.google.com/
>Lines: 103


>Message-ID: <2ea64ade.02102...@posting.google.com>
>References: <eKR#e1UcCHA.2052@tkmsftngp12> <xYJN8e7cCHA.1904@cpmsftngxa06>
<OrvI208cCHA.1652@tkmsftngp09> <OzFYyYDdCHA.392@tkmsftngp09>
<yKXbcgHdCHA.2320@cpmsftngxa06> <uRpinbKdCHA.1004@tkmsftngp08>
<uELG0BUdCHA.2248@tkmsftngp11>

<2ea64ade.02102...@posting.google.com>
<dxSM9WveCHA.2280@cpmsftngxa08>
>NNTP-Posting-Host: 12.228.165.217


>Content-Type: text/plain; charset=ISO-8859-1
>Content-Transfer-Encoding: 8bit

>X-Trace: posting.google.com 1035648672 13029 127.0.0.1 (26 Oct 2002
16:11:12 GMT)
>X-Complaints-To: groups...@google.com
>NNTP-Posting-Date: 26 Oct 2002 16:11:12 GMT
>Path:
cpmsftngxa09!cpmsftngxa06!tkmsftngp01!newsfeed00.sul.t-online.de!t-online.de
!news.stealth.net!news.stealth.net!news.maxwell.syr.edu!sn-xit-03!sn-xit-06!
sn-xit-08!sn-xit-04!supernews.com!postnews1.google.com!not-for-mail
>Xref: cpmsftngxa09
microsoft.public.dotnet.framework.aspnet.webcontrols:6693
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Brian Chapman

unread,
Nov 6, 2002, 7:52:07 PM11/6/02
to
Mike,

Thanks for the help, but I still haven't been able to figure this
out...this isn't a critical problem, I just want to understand what is
happening!

Here is some sample code using a custom control instead of a user
control (same problem). (link to code is at the bottom of the post)

Description:
In Page_Init, a web form loads a custom control containing link
buttons for a group of menu items. The user clicks on the "Links"
item and the command event is caught by the menu control which then
fires a custom event which is caught by the page. When the page
catches the event, it calls "LoadModule(...)" passing in the name of
the custom control to load, in this case, the "Links" control. The
links control is dynamically created and loaded in to a placeholder
control. A key is added to viewstate to note the control that was
most recently loaded. This key is checked in the Page_Load event so
the control can be reloaded each time the page is created.

The links control displays a datagrid that contains a list of
categories that the user can select. The user selects a category and
the data grid command event is fired. The control catches the event
and builds a second data grid with the links from the category that
was selected. Everything works fine. The user can select different
categories and the links show up. NOTE: I don't know if the design is
not correct and this is just working by chance.

If the user clicks the "Links" button in the menu control a second
time (or any number of times), it then takes 2 clicks on the link
category before the links will display.

So my question is, why?

Here is a link to the code: (code behind for the web page and the code
for the control)

http://brianchapman.homeip.net/bpweb/dropbox/code.zip

THANKS!

Brian

mic...@online.microsoft.com ("Mike Moore [MS]") wrote in message news:<Xb4$W5rfCHA.2484@cpmsftngxa08>...

Mike Moore [MS]

unread,
Nov 9, 2002, 12:11:16 AM11/9/02
to
Hi Brian

I looked through your code a bit, but I did not to fully study it. The
code-behind for the ASPX page shows that it has two place holders actually
on the page. Then it dynamically adds a "MenuControl" that is from
Microsoft Commerce Server (that's the only control I could find with that
name).

The custom control has two classes. The first one loads a dataset from an
XML file. It includes a couple DataGrid controls and an HtmlTable control.
It looks like it loads the DataGrids with data from the XML file and then
it puts the DataGrids into cells inside the HtmlTable. The second class is
a custom definition of eventargs which does not appear to be used anywhere.

In all, this isn't a very easy sample to work with, especially within the
somewhat limited scope of newsgroup posts. However, I did see one line that
looked suspicious: PlaceHolderModules.Controls.Clear();

If you look earlier in this same thread, we found that we had to remove
controls, not just clear them. Here's a snippet from the code sample in the
earlier post:


Public Sub RemoveAll(ByRef container As Control)
Dim ctl As Control
Dim x As Integer
For x = container.Controls.Count - 1 To 0 Step -1
ctl = container.Controls(x)
If ctl.HasControls Then
'do a recursive remove, we are removing the controls in the
container
'before removing the container
RemoveAll(ctl)
End If
container.Controls.Remove(ctl)
Next
End Sub
End Class

---
You wrote that the basics of your problem is a dynamically added control
which has an event that dynamically adds a custom control that also has an
event. The way I would approach this is to make it dramatically simpler. No
commerce server controls, or XML, or nested tables.

I would use a regular web button control as my initial dynamically added
control. Then I would create a very simple custom control to be added by
the server onclick event of my button. This custom control would have no
more than the minimum necessary to be visible on the client and to raise an
event. Perhaps I might have it render the HTML for a submit button to the
client.

I'm sorry that I can't study your sample in depth and I hope this helps.

Good luck with your project.

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------


>From: ripcu...@yahoo.com (Brian Chapman)
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>Subject: Re: Dynamic Controls - how to replace after their events fire

>Date: 6 Nov 2002 16:52:07 -0800
>Organization: http://groups.google.com/
>Lines: 72
>Message-ID: <2ea64ade.02110...@posting.google.com>


>References: <eKR#e1UcCHA.2052@tkmsftngp12> <xYJN8e7cCHA.1904@cpmsftngxa06>
<OrvI208cCHA.1652@tkmsftngp09> <OzFYyYDdCHA.392@tkmsftngp09>
<yKXbcgHdCHA.2320@cpmsftngxa06> <uRpinbKdCHA.1004@tkmsftngp08>
<uELG0BUdCHA.2248@tkmsftngp11>
<2ea64ade.02102...@posting.google.com>
<dxSM9WveCHA.2280@cpmsftngxa08>

<2ea64ade.02102...@posting.google.com>
<Xb4$W5rfCHA.2484@cpmsftngxa08>


>NNTP-Posting-Host: 12.228.165.217
>Content-Type: text/plain; charset=ISO-8859-1
>Content-Transfer-Encoding: 8bit

>X-Trace: posting.google.com 1036630327 16356 127.0.0.1 (7 Nov 2002
00:52:07 GMT)
>X-Complaints-To: groups...@google.com
>NNTP-Posting-Date: 7 Nov 2002 00:52:07 GMT
>Path:
cpmsftngxa09!cpmsftngxa08!tkmsftngp01!newsfeed00.sul.t-online.de!t-online.de
!newsfeed.icl.net!newsfeed.fjserv.net!newsfeed.icl.net!newsfeed.fjserv.net!n
ewsfeed1.cidera.com!Cidera!telocity-west!TELOCITY!sn-xit-03!sn-xit-01!sn-xit
-04!supernews.com!postnews1.google.com!not-for-mail
>Xref: cpmsftngxa09
microsoft.public.dotnet.framework.aspnet.webcontrols:6967
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Liz Patton

unread,
Nov 9, 2002, 11:43:08 AM11/9/02
to
This is a very interesting discussion. I'd like to do something very
similar, but was hoping not to have to write my own custom control;
I'd like to lay out my dynamic list controls in a Table (the number of
rows in the table is also dynamically dependent on a database). I
dynamically create the containers, then dynamically add Image buttons,
with an onclick handler, then that handler adds still more dynamically
created controls.

I found that the control added like this:
Me.Controls(1).Controls.Add(TextBox1)
Works and maintains its state through the post-back. This is adding
the control to the Page container, right? There's no control over the
layout of the controls. But when I similarly add controls to a
container
that was also created dynamically, such as a Panel or a Table control,
the control is lost upon postback. Is there a way around this?

Below is a link to a post that explains more fully what I want to do.

Thanks,

http://groups.google.com/groups?as_q=Nested%20control%20in%20asp%3Atable%20fails%20to%20maintain%20state%20through%20postback&safe=images&ie=ISO-8859-1&as_ugroup=microsoft.public.dotnet.framework.*&lr=&hl=en

"Brad" <nos...@co.lane.or.us> wrote in message news:<OrvI208cCHA.1652@tkmsftngp09>...

Brian Chapman

unread,
Nov 9, 2002, 7:17:28 PM11/9/02
to
Mike,

I apologize for the confusion...I've been using the same project for
all kinds of tests, so things became a little screwed up!

As you suggested, I created a very simple example that exhibits the
same behavior. I used a UserControl instead because it was easier.

Please let me know if you have any suggestions! Thanks. Brian

WebForm:
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.PlaceHolder PlaceHolder1;
protected System.Web.UI.WebControls.PlaceHolder PlaceHolder2;

public WebForm1()
{
this.Load += new System.EventHandler(this.Page_Load);
}

private void Page_Load(object sender, System.EventArgs e)
{
if ( (String)ViewState["Control"] != null &&
! ((String)ViewState["Control"]).Equals(""))
{
PlaceHolder2.Controls.Add(LoadControl((String)ViewState["Control"]));
}
}

protected void Page_Init(object sender, System.EventArgs args)
{
LinkButton lb = new LinkButton();
lb.Text = "Click";
lb.Click += new System.EventHandler(this.OnPageLinkButtonClicked);
PlaceHolder1.Controls.Add(lb);
}

protected void OnPageLinkButtonClicked(object sender,
System.EventArgs e)
{
foreach ( Control c in PlaceHolder2.Controls )
{
PlaceHolder2.Controls.Remove(c);
}

PlaceHolder2.Controls.Add(LoadControl("WebUserControl2_TEST.ascx"));
ViewState.Add("Control", "WebUserControl2_TEST.ascx");
}

User Control:
public abstract class WebUserControl2_TEST : System.Web.UI.UserControl
{
public WebUserControl2_TEST()
{
this.Init += new System.EventHandler(this.Page_Init);
}

private void Page_Init(object sender, System.EventArgs e)
{
LinkButton b = new LinkButton();
b.Text = "Ctrl";
b.Click += new System.EventHandler(this.OnButtonClick);
Controls.Add(b);
}

protected void OnButtonClick(object sender, System.EventArgs e)
{
Label l = new Label();
l.Text = "Test";
Controls.Add(l);
}
}

mic...@online.microsoft.com ("Mike Moore [MS]") wrote in message news:<gUQpB56hCHA.2704@cpmsftngxa06>...

Brian Chapman

unread,
Nov 9, 2002, 7:24:11 PM11/9/02
to
You're definately going to have to store which dropdown lists have
already been loaded and their selections in ViewState (or somewhere)
so that you can reload them every time the page is posted. I'm not
aware of any other way of doing it.

If you look at the sample code I posted (in response to the message
you responded to from Mike) you see that to make sure that the
dynamically loaded usercontrol is re-added to the page each time, that
I store in ViewState that it has been added. I then re-load the
control for every post back after that. I think you'll have to do the
same, just with a more information in ViewState.

It get's pretty tricky when you're adding lots of controls
dynamically!

Brian

mong...@hotmail.com (Liz Patton) wrote in message news:<40870380.02110...@posting.google.com>...

Brian Chapman

unread,
Nov 10, 2002, 2:07:21 PM11/10/02
to
By same behavior, I mean that the first time you click the link button
on the web form to load the control, it takes one click on the button
in the control to display the test. If, immediately afterward, the
link button on the form is clicked and the control is loaded again, it
then takes two clicks before the text is displayed.

Brian

ripcu...@yahoo.com (Brian Chapman) wrote in message news:<2ea64ade.0211...@posting.google.com>...

Mike Moore [MS]

unread,
Nov 14, 2002, 9:11:52 PM11/14/02
to
Hi Brian,

I'm sorry for taking so long to get back to you. I just looked at your new
code. It is much easier to work with, thank you.

I created a user control with your code and pasted your web form code into
the code-behind of a web form. I changed the class names to match the name
of my web form.

When I tried your code, I found that the web-form code Page_Init event did
not fire. I then noticed that you removed the auto-generated OnInit event
and replaced it with an event with the same name as the class. You did this
with both the web form code and the user control code. So, added the
following line to the event with the same name as the class:
this.Init += new System.EventHandler(this.Page_Init);

Now I have the following behavior:
1 browse the page -- it shows a link button with text "click"
2 click the button -- it shows two buttons, "click" and "ctrl"
3 click "ctrl" -- it shows "click", "ctrl" and "test" (which is a label)
4 click "click" again -- it shows "click" and "ctrl"
5 click "ctrl" -- it FAILS to show test (just "click" and "ctrl")
6 click "ctrl" again -- it shows all three controls (including "test") as
it's supposed to

So, the problem is the second attempt to click the "ctrl" button fails to
display "test".
This means that, in step 5, the button dynamically added to the user
control fails to fire its own event.

----
I've looked at this and have not yet determined why it is happening. I will
look into it further tomorrow.

Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------


>From: ripcu...@yahoo.com (Brian Chapman)
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>Subject: Re: Dynamic Controls - how to replace after their events fire

>Date: 10 Nov 2002 11:07:21 -0800
>Organization: http://groups.google.com/
>Lines: 143
>Message-ID: <2ea64ade.02111...@posting.google.com>
>References: <eKR#e1UcCHA.2052@tkmsftngp12> <OrvI208cCHA.1652@tkmsftngp09>

<OzFYyYDdCHA.392@tkmsftngp09> <yKXbcgHdCHA.2320@cpmsftngxa06>
<uRpinbKdCHA.1004@tkmsftngp08> <uELG0BUdCHA.2248@tkmsftngp11>
<2ea64ade.02102...@posting.google.com>
<dxSM9WveCHA.2280@cpmsftngxa08>
<2ea64ade.02102...@posting.google.com>
<Xb4$W5rfCHA.2484@cpmsftngxa08>

<2ea64ade.02110...@posting.google.com>
<gUQpB56hCHA.2704@cpmsftngxa06>
<2ea64ade.0211...@posting.google.com>


>NNTP-Posting-Host: 12.228.165.217
>Content-Type: text/plain; charset=ISO-8859-1
>Content-Transfer-Encoding: 8bit

>X-Trace: posting.google.com 1036955242 10084 127.0.0.1 (10 Nov 2002
19:07:22 GMT)
>X-Complaints-To: groups...@google.com
>NNTP-Posting-Date: 10 Nov 2002 19:07:22 GMT
>Path:
cpmsftngxa06!tkmsftngp01!newsfeed00.sul.t-online.de!t-online.de!newsfeed.icl
net!newsfeed.fjserv.net!c02.atl3!news.webusenet.com!telocity-west!TELOCITY!
sn-xit-03!sn-xit-01!sn-xit-04!supernews.com!postnews1.google.com!not-for-mai
l
>Xref: cpmsftngxa06
microsoft.public.dotnet.framework.aspnet.webcontrols:7050
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

Brian Chapman

unread,
Nov 15, 2002, 3:27:06 PM11/15/02
to
Great! At least you're able to replicate the behavior with the new
code.

As far as moving the registration of the Init event to the constructor
(name of the web form)...I did that because VS.NET occassionally was
not auto-generating the OnInit event. I looked around for a bit and
found that the IBuySpyPortal code was registering for the Init event
in the constructor...so I went with that method. It seems to have
worked so far.

Thanks for the help, and please let me know what you find.

Brian

mic...@online.microsoft.com ("Mike Moore [MS]") wrote in message news:<9exWrwEjCHA.2340@cpmsftngxa08>...

Mike Moore [MS]

unread,
Nov 15, 2002, 8:31:26 PM11/15/02
to
Hi Brian,

QUESTION
I have a dynamically added button control (btn). The second time I click
this button, its server-side click event fails to execute.

First, my form already has a button (Button1). The server-side click event
for "Button1" adds "btn". On further post backs, "btn" is re-added in the
Page_Load event. The failure occurs the first time "btn" is added via the
Page_Load event, when it was previously added in the Button1 click event.

ANSWER
It turns out that this can happen any time that a control is dynamically
added in different places within your code. In this case, it is sometimes
added in the first button's click event and other times added in the
Page_Load event. Here are the related snippets from your code sample:

* Page_Load
PlaceHolder2.Controls.Add(LoadControl((String)ViewState["Control"]));
//[where the value from ViewState is: "WebUserControl2_TEST.ascx"

* OnPageLinkButtonClicked
PlaceHolder2.Controls.Add(LoadControl("WebUserControl2_TEST.ascx"));

The fix for this is to give the control an ID in your code so that it
receives the same ID every time it is added. Otherwise, .NET will determine
an ID for you. This is generally fine if your control is always added by
the same line of code. However, your control is sometimes added by a line
of code in Page_Load, and other times added in a line of code in
OnPageLinkButtonClicked.

Here is the replacement code snippets that fix this problem:

* Page_Load
System.Web.UI.UserControl ctl = (System.Web.UI.UserControl)
LoadControl((String)ViewState["Control"]);
ctl.ID = "MyControl";
PlaceHolder2.Controls.Add(ctl);
//[where the value from ViewState is: "WebUserControl2_TEST.ascx"

* OnPageLinkButtonClicked
System.Web.UI.UserControl ctl = (System.Web.UI.UserControl)
LoadControl("WebUserControl2_TEST.ascx");
ctl.ID = "MyControl";
PlaceHolder2.Controls.Add(ctl);


CODE SAMPLE:

***** User control (WebUserControl2_TEST.ascx)

* Do nothing. Just leave it empty, as it already is.

***** Code-behind for WebUserControl2_TEST.ascx

namespace nTest3
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for WebUserControl2_TEST.
/// </summary>


public abstract class WebUserControl2_TEST : System.Web.UI.UserControl
{
public WebUserControl2_TEST()
{
this.Init += new System.EventHandler(this.Page_Init);
}

private void Page_Init(object sender, System.EventArgs e)
{
LinkButton b = new LinkButton();
b.Text = "Ctrl";
b.Click += new System.EventHandler(this.OnButtonClick);
Controls.Add(b);
}

protected void OnButtonClick(object sender, System.EventArgs e)
{
Label l = new Label();
l.Text = "Test";
Controls.Add(l);
}

}
}


***** ASPX (wc2_test.aspx)

* Add two place holder controls to the ASPX page


***** Code-behind for wc2_test.aspx

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace nTest3
{
/// <summary>
/// Summary description for wc2_test.
/// </summary>
public class wc2_test : System.Web.UI.Page


{
protected System.Web.UI.WebControls.PlaceHolder PlaceHolder1;
protected System.Web.UI.WebControls.PlaceHolder PlaceHolder2;

public wc2_test()
{
this.Init += new System.EventHandler(this.Page_Init);
this.Load += new System.EventHandler(this.Page_Load);
}

private void Page_Load(object sender, System.EventArgs e)
{
if ( (String)ViewState["Control"] != null &&
! ((String)ViewState["Control"]).Equals(""))
{

System.Web.UI.UserControl ctl = (System.Web.UI.UserControl)
LoadControl((String)ViewState["Control"]);
ctl.ID = "MyControl";
PlaceHolder2.Controls.Add(ctl);
}
}

protected void Page_Init(object sender, System.EventArgs args)
{
LinkButton lb = new LinkButton();
lb.Text = "Click";
lb.Click += new System.EventHandler(this.OnPageLinkButtonClicked);
PlaceHolder1.Controls.Add(lb);
}

protected void OnPageLinkButtonClicked(object sender,
System.EventArgs e)
{
foreach ( Control c in PlaceHolder2.Controls )
{
PlaceHolder2.Controls.Remove(c);
}

System.Web.UI.UserControl ctl = (System.Web.UI.UserControl)
LoadControl("WebUserControl2_TEST.ascx");
ctl.ID = "MyControl";
PlaceHolder2.Controls.Add(ctl);


ViewState.Add("Control", "WebUserControl2_TEST.ascx");
}
}
}

***** end of code sample


Thank you, Mike Moore
Microsoft, ASP.NET

This posting is provided "AS IS", with no warranties, and confers no rights.

--------------------
>From: ripcu...@yahoo.com (Brian Chapman)
>Newsgroups: microsoft.public.dotnet.framework.aspnet.webcontrols
>Subject: Re: Dynamic Controls - how to replace after their events fire

>Date: 15 Nov 2002 12:27:06 -0800
>Organization: http://groups.google.com/
>Lines: 256
>Message-ID: <2ea64ade.02111...@posting.google.com>
>References: <eKR#e1UcCHA.2052@tkmsftngp12> <uRpinbKdCHA.1004@tkmsftngp08>

<uELG0BUdCHA.2248@tkmsftngp11>
<2ea64ade.02102...@posting.google.com>
<dxSM9WveCHA.2280@cpmsftngxa08>
<2ea64ade.02102...@posting.google.com>
<Xb4$W5rfCHA.2484@cpmsftngxa08>
<2ea64ade.02110...@posting.google.com>
<gUQpB56hCHA.2704@cpmsftngxa06>
<2ea64ade.0211...@posting.google.com>

<2ea64ade.02111...@posting.google.com>
<9exWrwEjCHA.2340@cpmsftngxa08>
>NNTP-Posting-Host: 208.247.148.12


>Content-Type: text/plain; charset=ISO-8859-1
>Content-Transfer-Encoding: 8bit

>X-Trace: posting.google.com 1037392026 10724 127.0.0.1 (15 Nov 2002
20:27:06 GMT)
>X-Complaints-To: groups...@google.com
>NNTP-Posting-Date: 15 Nov 2002 20:27:06 GMT
>Path:
cpmsftngxa08!tkmsftngp01!newsfeed00.sul.t-online.de!t-online.de!news-spur1.m
axwell.syr.edu!news.maxwell.syr.edu!newsfeed-west.nntpserver.com!hub1.megane
tnews.com!nntpserver.com!telocity-west!TELOCITY!sn-xit-03!sn-xit-01!sn-xit-0
4!supernews.com!postnews1.google.com!not-for-mail
>Xref: cpmsftngxa08
microsoft.public.dotnet.framework.aspnet.webcontrols:7240
>X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet.webcontrols

0 new messages