Dynamically add user control under UpdatePanel in ASP.NET

There are many ways to do this in ASP.NET. I have to say this is a complicated topic for me.

I am not going to tell you all sorts of ways to accomplish this since some guys out there have already done this. And I learned from them. Here is how I like to do it.

I would like to give some important background first.

Page life cycle (simplify) : Init->Load viewstate->Load->Save viewstate->Event Handler

Viewstate : properties and values of your controls, event handler included!

Postback : the page life cycle will be gone through in each postback, so, if you have add some controls dynamically, you have to do the same in the follow up postbacks.

Events : The event handler works with the control’s id, the id is generated according to how you add them, so the ordering of adding controls is crucial.

That is all you need to know. So it would be wise to add you controls at Init stage if it is possible. If you add your controls at Load stage, you will need to add event handlers for them manually. This will be a large load of work that I will avoid. I will now go through how to add control.

It is very likely that you click something or have some events, then you want some controls to appear. The event handler may be your first choice putting in your dynamic add controls code. But this lead to a problem, event handler comes later then Page_Load, don’t even mention Page_Init is even before that. So, I use a work around which is about _doPostBack. Most of the postback involved a Javascript function _doPostBack(). It will pass two parameters to you Page object, which are __EVENTTARGET and __EVENTARGUMENT. __EVENTTARGET is the control that trigger the postback and __EVENTARGUMENT is the value it contains. This is what I do.

public partial class myPage : System.Web.UI.Page
{
   public myPage()
   {
      //add a event handler to the Page Init event
      Init += new EventHandler(Page_MyInit);
   }
   protected void Page_MyInit(object sender, EventArgs e)
   {
       //get the values of the control Id and it's value
       string target = Request.Params.Get("__EVENTTARGET");
       string argument = Request.Params.Get(__EVENTARGUMENT); 
       //add dynamic controls if the event is what you want
       if( ...check target and argument...)
       {
            //I like to use place holder to handle dynamic controls, just add a static place holder
            Control uc1 = Page.LoadControl( ...path of your control... );
            placeHolder1.Controls.Add(uc1);
       }
   }
}

This should let you add your controls just fine. If your postback is not using _doPostBack, you can try another approach by Request.Form and loop through it. dev|sushi posts have cover that. And now we need to add those controls in each postback to keep them on the page, I use the dumbest approach which is remembering the controls I have added in the session and check them in Page_Init. Add the following just after the above if {}

if (Session["whatever"] != null && !isFirstTime)
{
    ... add user control just like before ...
}

There is one thing you need to beware, this make me head ache for a day. remenber don’t do this.

if( ...check target and argument...) { add control a }
if( ...check target and argument...) { add control b }
if( ...check target and argument...) { add control c }
if (Session["whatever"] != null && !isFirstTime) { add control a}
if (Session["whatever"] != null && !isFirstTime) { add control b}
if (Session["whatever"] != null && !isFirstTime) { add control c}

This will mess up your controls ordering, do this instead

if( ...check target and argument...) { add control a }
if (Session["whatever"] != null && !isFirstTime) { add control a}
if( ...check target and argument...) { add control b }
if (Session["whatever"] != null && !isFirstTime) { add control b}
if( ...check target and argument...) { add control c }
if (Session["whatever"] != null && !isFirstTime) { add control c}

As for the viewstate, I recommend you clear it whenever you don’t need it. I simply call Viewstate.Clear() when user click on the menu. Or disable viewstate on dynamic controls by Control.EnableViewState = false when you are using UpdatePanel. Because UpdatePanel will do it for you with javascript. But beware when you design your user controls, give each control and their sub controls a unique id. I think UpdatePanel is restoring values by component’s id which is a common way of ajax. I had a id conflict and it gives me Sys.WebForms.PageRequestManagerServerErrorException.

I hope this helps. ^^

Advertisements

ASP.NET Add UserControl with AJAX

If you are using .Net 3.5, you can enable ajax easily.

I am going to talk about addina user control .ascx to your web application without refreshing the whole page. I use this to achieve ajax navigation of my content pages. simply make your content pages into .ascx and dynamically add the user control to your page. I am using this with master page but won’t talk about master page here.

Fisrt, you will have to create a solution using .Net framework 3.5. you will need two object,

the ScriptManager which manage javascript and the UpdatePanel where you put ajax enable objects in it. You also have to add ContentTemplate tag inside update panel in order to make this work.

Create your .ascx, add a PlaceHolder at where you want your .ascx being added and add an object that trigger an event, and do the dynamic addition of user control inside the event handler. Such as adding a button and then double click it, the IDE will take you to the click event handler.

This is how you load and add your user control.

UpdatePanel updatePanel = (UpdatePanel)Page.FindControl("updatePanelId");
Control userControl = Page.LoadControl("path to your .ascx"); //e.g. @"~/usercontrol.ascx"
placeHolder.Controls.Add(userControl);

you are now able to add user control but your page will be refreshed. Because we didn’t register our trigger control. I think there are about 3 ways you can do this. I do it in the way which I think is the simplest.

Inside your page_load() method, write this

scriptManager.RegisterAsynPostBackControl(button);

you can now see that your user control is being add with ajax. But if any postback occur, the user control will just disappear. This is because every time a postback occur, the page is re-render with the controls tree in the Page object. I am not going inside to explain the details, here is what I do.

you store the dynamic add user control information in your session, then inside page_load() you check that information, then add the dynamic control there.

add this at the end of the first piece of code snippet.

Session["virtualPath"] = "path to your .ascx"

then in you page_load(), write something like this.

if (Session["virtualPath"] != null)
{
Control userControl = Page.LoadControl(Session["virtualPath"]);
placeHolder.Controls.Add(userControl);
}

Because we are adding it with ajax, I don’t think you need to do anything to keep the values inside your user control. If they disappear and you what to keep them, you may try to move those code inside page_load() to the viewstate event handler.

^^ I will write about generating .xlsx on the fly inside memory with OpenXml SDK V2 CTP when I have time. See ya.