[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

When to add dynamically loaded controls?

Posted on 2009-04-15
5
Medium Priority
?
934 Views
Last Modified: 2013-11-08
In an ASP.NET page, I have an UpdatePanel with dynamically a loaded child control (using the Page.LoadControl method). I know I have to create the control and add it to the page after every postback (even asynchronous), but there seems to be one of two problem regarding when, in the lifecycle of the page I do this.
A) If I create the control during the page's OnInit (or CreateChildControls or OnLoad) phase, events in the parent page have not been processed yet, so I don't know exactly which control to load.
B) If I create the control during the page's OnPreRender(or OnLoadComplete)  phase, things look fine, but the dynamic control will not respond to any postback events.

When it the preferred time in a page's lifecycle to create dynamically loaded controls?
'Here is a summary of the important methods
 
 
'This function only gets called if the viewer is created during initialization
Protected Overrides Function OnBubbleEvent(ByVal source As Object, ByVal e As EventArgs) As Boolean
  Dim handled As Boolean = False
  If TypeOf e Is CommandEventArgs Then
    Dim ce As CommandEventArgs = DirectCast(e, CommandEventArgs)
    Select Case ce.CommandName
       Case "Show"
       ViewerCode = ce.CommandArgument
        handled = True
    End Select
  End If
  Return handled
End Function
 
 
'SomeSub is any procedure in the page's lifecycle
Protected Overrides Sub SomeSub()
  If _viewer Is Nothing Then
    LoadViewer()
  End If
  MyBase.SomeSub()
End Sub
 
 
Private Sub LoadViewer()
  Dim ViewerPath As String = DecodeViewerPath(ViewerCode)
  _viewer =Page.LoadControl(ViewerPath)
  ViewerUpdatePanel.ContentTemplateContainer.Controls.Clear()
  ViewerUpdatePanel.ContentTemplateContainer.Controls.Add(_viewer)
  ViewerUpdatePanel.Update()
End Sub
 
 
'This function only gets called in the right order if the viewer is created after initialization
Private Sub TreeView_SelectedNodeChanged(ByVal sender As Object, ByVal e As EventArgs)  Handles TreeView.SelectedNodeChanged
  ViewerCode = TreeView.SelectedNode.Value
End Sub

Open in new window

0
Comment
Question by:OFGemini
  • 3
  • 2
5 Comments
 

Author Comment

by:OFGemini
ID: 24152343
I've fixed the problem tentatively by reorganizing the code. Basically, I'm creating the dynamic control twice if the ViewerCode should change.

I'm still looking for a better, cleaner solution.
'Create the viewer every time on load
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
  LoadViewer()
  MyBase.OnLoad(e)
End Sub
 
'Recreate it if we have to
Private Sub ShowViewer(ByVal code As String)
  If _viewer IsNot Nothing Then
    _viewer.Dispose()
    _viewer = Nothing
  End If
  ViewerCode = code
  LoadViewer()
  ViewerUpdatePanel.Update()
End Sub
 
Protected Overrides Function OnBubbleEvent(ByVal source As Object, ByVal e As EventArgs) As Boolean
  Dim handled As Boolean = False
  If TypeOf e Is CommandEventArgs Then
    Dim ce As CommandEventArgs = DirectCast(e, CommandEventArgs)
    Select Case ce.CommandName
       Case "Show"
       ShowViewerCode(ce.CommandArgument)
       handled = True
    End Select
  End If
  Return handled
End Function
 
Private Sub TreeView_SelectedNodeChanged(ByVal sender As Object, ByVal e As EventArgs) Handles TreeView.SelectedNodeChanged
  ShowViewer(TreeView.SelectedNode.Value)
End Sub

Open in new window

0
 
LVL 15

Expert Comment

by:NazoUK
ID: 24156665
Dynamically created controls can be tricky for exactly the reasons you say.
It's ok to add a dynamic control in say, a button click event handler, but if the control you add raises a postback itself then in the next postback it must be added to the page before postback events are raised, which happens after page_load and before prerender.

As an example, say I have a button on my page which when clicked adds a dynamic control, which itself has a button in it, the process would need to be:

(Page button click)
Page_Init -> (do nothing)
Button_Click -> Add the dynamic control.

(Dynamic control button click)
Page_Init -> Add the dynamic control.

The tricky part here is how to handle the logic of adding the control in different page events depending on the circumstances. I'd suggest adding a value to viewstate which specifies whether you need to create the control, you can then check this each postback to detarmine whether to recreate the control. So the above would become:

(Page button click)
Page_Init -> Check Viewstate("ControlToCreate") -> nothing required
Button_Click -> Add the dynamic control. Set Viewstate("ControlToCreate")

(Dynamic control button click)
Page_Init -> Check Viewstate("ControlToCreate") -> Create required control.

Hope this helps.
0
 

Author Comment

by:OFGemini
ID: 24159607
This seems to be very similar to the solution I'd posted (only you suggest using Init rather than Load), correct? I should point out that in my snippet, ViewerCode just is a wrapper for a viewstate variable

On_Init (On_Load) -> read viewstate, create controls
On_Some_PB_Event -> set viewstate, create controls

This still seems a little bit clumsy as the 'create controls' step could be (or in my case, is likely to be) fairly expensive. Unless someone can suggest an alternative solution, this will have to do.
Private Property ViewerCode() As String
  Get
    Return Return If(CStr(ViewState("ViewerCode")), String.Empty)
  End Get
  Set(ByVal value As String)
    ViewState("ViewerCode") = value
  End Set
End Property

Open in new window

0
 
LVL 15

Accepted Solution

by:
NazoUK earned 2000 total points
ID: 24160989
Are there definite conditions where you know the current control should not be persisted?
You could check the form variables to find out what control initiated the postback. Request.Form("__EventTarget") will tell you the control that caused the postback if it was a javascript fired postback (i.e. linkbuttons or controls with AutoPostBack set). Setting UseSubmiteBehaviour="false" on buttons will also cause this behaviour, otherwise you can check the form collection for the clientid (or maybe uniqueid, not sure off the top of my head) of each button.

If this information is enough to determine whether to recreate the control then it sounds doable, otherwise I don't see a way around creating them twice.
0
 

Author Comment

by:OFGemini
ID: 24161521
In short, no, it's not enough. I already rely on events bubbling up through the dynamic control without knowing precisely where the event originated.

I light of this, I suppose there is no good work around.
0

Featured Post

NFR key for Veeam Backup for Microsoft Office 365

Veeam is happy to provide a free NFR license (for 1 year, up to 10 users). This license allows for the non‑production use of Veeam Backup for Microsoft Office 365 in your home lab without any feature limitations.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

OverviewThis article demonstrates a simple search form using AJAX. The purpose of the article is to demonstrate how to use the same code to render a page and javascript (JQuery) and AJAX to make subsequent calls to refine the results. The princip…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Loops Section Overview
When cloud platforms entered the scene, users and companies jumped on board to take advantage of the many benefits, like the ability to work and connect with company information from various locations. What many didn't foresee was the increased risk…
Suggested Courses
Course of the Month17 days, 17 hours left to enroll

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question