Amit's Blog

Sharing Thoughts and Learning

  Home  |   Contact  |   Syndication    |   Login
  43 Posts | 0 Stories | 233 Comments | 14 Trackbacks

News

About Me?
Read it in
Blog Statistics
Proud Member of

Tag Cloud


Archives

Post Categories

Articles

Book Review

I Visit.

OpenSource Project(s)

In this post, I will show you how to load different user control in UpdatePanel from different menu item click. I have found a lot of request in Asp.net Ajax Forum and some of them are having misconception about this. Once you complete reading this post you will be able to load controls dynamically and learn how to employ different helper controls like UpdateProgress, ModalPopupExtender while the UserControl is loading. First let us create plain page without the ajax support:

Markup:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PlainSampleMenu.aspx.cs" Inherits="PlainSampleMenuPage" %>
<!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">
    <title>Plain Sample Menu</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Menu ID="Menu1" runat="server" OnMenuItemClick="Menu1_MenuItemClick">
            <Items>
                <asp:MenuItem Text="File">
                    <asp:MenuItem Text="Load Control1"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control2"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control3"></asp:MenuItem>
                </asp:MenuItem>
            </Items>
        </asp:Menu>
        <br />
        <br />
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
    </form>
</body>
</html>

Code Behind:

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class PlainSampleMenuPage : System.Web.UI.Page
{
    private const string BASE_PATH = "~/DynamicControlLoading/";

    private string LastLoadedControl
    {
        get
        {
            return ViewState["LastLoaded"] as string;
        }
        set
        {
            ViewState["LastLoaded"] = value;
        }
    }

    private void LoadUserControl()
    {
        string controlPath = LastLoadedControl;

        if (!string.IsNullOrEmpty(controlPath))
        {
            PlaceHolder1.Controls.Clear();
            UserControl uc = (UserControl)LoadControl(controlPath);
            PlaceHolder1.Controls.Add(uc);
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        LoadUserControl();
    }

    protected void Menu1_MenuItemClick(object sender, MenuEventArgs e)
    {
        MenuItem menu = e.Item;

        string controlPath = string.Empty;

        switch (menu.Text)
        {
            case "Load Control2":
                controlPath = BASE_PATH + "SampleControl2.ascx";
                break;
            case "Load Control3":
                controlPath = BASE_PATH + "SampleControl3.ascx";
                break;
            default:
                controlPath = BASE_PATH + "SampleControl1.ascx";
                break;
        }

        LastLoadedControl = controlPath;
        LoadUserControl();
    }
}

As you can see we are loading the UserControls in the PlaceHolder Control on different menu item click. If you are wondering why I am also loading the controls in Page Load event based upon the ViewState, the reason is otherwise those dynamically loaded controls will not be visible in the consequent postbacks. There are few good articles written by Scott Mitchell on dynamically loading Controls which you will find in the following links:

Now let us ajaxify this page, lets wrap the PlaceHolder with an UpdatePanel control. The following shows the markup:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SampleMenu1.aspx.cs" Inherits="SampleMenuPage1" %>
<!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">
    <title>Sample Menu</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Menu ID="Menu1" runat="server" OnMenuItemClick="Menu1_MenuItemClick">
            <Items>
                <asp:MenuItem Text="File">
                    <asp:MenuItem Text="Load Control1"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control2"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control3"></asp:MenuItem>
                </asp:MenuItem>
            </Items>
        </asp:Menu>
        <br />
        <br />
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Menu1" />
            </Triggers>
        </asp:UpdatePanel>
    </form>
</body>
</html>

Since the Menu control resides outside the UpdatePanel we will also need a AsyncPostBackTrigger for the Menu Control. Now run this page, you will find the controls are loaded without a full postback.

Now let us further enhance this page with UpdateProgress and AjaxControlToolKit's ModalPopupExtender. First with the UpdateProgress Control.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SampleMenu1.aspx.cs" Inherits="SampleMenuPage1" %>
<!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">
    <title>Sample Menu - UpdateProgress</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Menu ID="Menu1" runat="server" OnMenuItemClick="Menu1_MenuItemClick">
            <Items>
                <asp:MenuItem Text="File">
                    <asp:MenuItem Text="Load Control1"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control2"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control3"></asp:MenuItem>
                </asp:MenuItem>
            </Items>
        </asp:Menu>
        <br />
        <br />
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
                    <ProgressTemplate>
                        Loading....
                    </ProgressTemplate>
                </asp:UpdateProgress>
                <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Menu1" />
            </Triggers>
        </asp:UpdatePanel>
    </form>
</body>
</html>

As you can see we have added a UpdateProgress Control in the UpdatePanel ContentTemplate. But the UpdateProgress does not get visible when you click any of the menu item. This is the true nature of UpdatePanel, it does not shows the UpdateProgress if the control is out side the UpdatePanel which caused the postback. We have to manually show the UpdateProgress by the JavaScript code like the following:

<script type="text/javascript">

    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_initializeRequest(initializeRequest);
    prm.add_endRequest(endRequest);

    var _postBackElement;

    function initializeRequest(sender, e)
    {
        if (prm.get_isInAsyncPostBack())
        {
            e.set_cancel(true);
        }

        _postBackElement = e.get_postBackElement();

        if (_postBackElement.id.indexOf('Menu1') > -1)
        {
            $get('UpdateProgress1').style.display = 'block';
        }
    }

    function endRequest(sender, e)
    {
        if (_postBackElement.id.indexOf('Menu1') > -1)
        {
            $get('UpdateProgress1').style.display = 'none';
        }
    }
</script>

Now run the page, you will find the UpdateProgress Control is showing the loading message no matter which control caused the postback.

In this final section we will implement the AjaxControlToolKit's ModalPopupExtender to show the loading message, this will give you a similar look of CodePlex Site. The following shows the source:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SampleMenu2.aspx.cs" Inherits="SampleMenuPage2" %>
<!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">
    <title>Sample Menu - ModalPopupExtender</title>
    <style type="text/css">
        .modalBackground
        {
            background-color:#dcdcdc;
            filter:alpha(opacity=60);
            opacity:0.60;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Menu ID="Menu1" runat="server" OnMenuItemClick="Menu1_MenuItemClick">
            <Items>
                <asp:MenuItem Text="File">
                    <asp:MenuItem Text="Load Control1"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control2"></asp:MenuItem>
                    <asp:MenuItem Text="Load Control3"></asp:MenuItem>
                </asp:MenuItem>
            </Items>
        </asp:Menu>
        <br />
        <br />
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Menu1" />
            </Triggers>
        </asp:UpdatePanel>
        <asp:Panel ID="Panel1" runat="server" style="background-color:#ffffff;display:none;width:400px">
            <div style="padding:8px">
                <h2>Loading...</h2>
            </div>
        </asp:Panel>
        <ajaxToolKit:ModalPopupExtender ID="ModalPopupExtender1" runat="server" TargetControlID="Panel1" PopupControlID="Panel1" BackgroundCssClass="modalBackground" DropShadow="true" />
        <script type="text/javascript">

            var prm = Sys.WebForms.PageRequestManager.getInstance();

            prm.add_initializeRequest(initializeRequest);
            prm.add_endRequest(endRequest);

            var _postBackElement;

            function initializeRequest(sender, e)
            {
                if (prm.get_isInAsyncPostBack())
                {
                    e.set_cancel(true);
                }

                _postBackElement = e.get_postBackElement();

                if (_postBackElement.id.indexOf('Menu1') > -1)
                {
                    $find('ModalPopupExtender1').show();
                }
            }

            function endRequest(sender, e)
            {
                if (_postBackElement.id.indexOf('Menu1') > -1)
                {
                    $find('ModalPopupExtender1').hide();
                }
            }
        </script>
    </form>
</body>
</html>

As you can see we first created a custom style which will be shown as the background style when the modal popup is visible, next we have added a regular Asp.net Panel control which will be shown as the modal popup. We have initially set the Panel control display mode to none, so there will be no flicker when the modal popup is shown. At last, we have added a ModalPopupExtender and sets its required property. The previous rule also applies here, we have to manually show/hide the ModalPopup which we are doing in the above JavaScript code. You will also found few cool techniques of ModalPopupExtender in this link.

To run the sample first create a AjaxControlToolKit enable site website then create a folder DynamicControlLoading folder and copy the files in the following attachment.

Download: Complete Source

kick it on DotNetKicks.com

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
posted on Saturday, August 11, 2007 8:48 PM

Feedback

# re: Loading UserControl Dynamically in UpdatePanel 8/16/2007 2:37 PM Sridhar Bommana
Hi,

I tried using UpdatePanel code...
Things work fine. But when I debug, I see the PageLoad event being fired twice...

Is this the nature of the UpdatePanel control?

Thanks,
Sridhar

# re: Loading UserControl Dynamically in UpdatePanel 8/16/2007 4:50 PM Kazi Manzur Rashid
yes the pageload event in the client side fires for every asyncpostback.

# re: Loading UserControl Dynamically in UpdatePanel 8/16/2007 10:23 PM afromobile
i've got some yui javascript in SampleControl2.ascx but it doesn't fire. it'll fire if i put it in the default controls' prm.add_pageLoaded function.

what do i need to do?

# re: Loading UserControl Dynamically in UpdatePanel 8/20/2007 3:27 AM Yuriy
Hi,
If your usercontrol includes any TextBoxes or other controls with postback data, you will not be able to use these values immediately in the Page_Load. Unfortunatelly, in large applications in may be very significant problem. To overcome this problem it is better during postback to load user control in overridden LoadViewState method after calling base.LoadViewState. In this case you do load it before postback data are handled and user control comes loaded to Page_load event.


# re: Loading UserControl Dynamically in UpdatePanel 8/20/2007 3:36 AM Kazi Manzur Rashid
Thanks for pointing out this Yuriy.

# re: Loading UserControl Dynamically in UpdatePanel 10/1/2007 12:04 AM Sidney
Hi,

Nice article, but I was wondering what do i need to do if I'm trying to load multiple user control in one event? Can you help me out? co'z it's not working i'm getting an error:

Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.



# re: Loading UserControl Dynamically in UpdatePanel 12/11/2007 7:03 AM waflarz
Article was very useful,
However it is missing important line of code:
in the LoadUserControl() method you need to set the control ID or you will be loosing postbacks within user controls
e.g.
UserControl uc = (UserControl)LoadControl(controlPath);
uc.ID = "dummyID";

Thanks

# re: Loading UserControl Dynamically in UpdatePanel 1/7/2008 1:06 PM Ashraf
Nice example, Helps a lot. Thanks man

# re: Loading UserControl Dynamically in UpdatePanel 1/31/2008 3:25 AM vinyl outdoor shutters
This article really helped out a lot. Thanks.

# re: Loading UserControl Dynamically in UpdatePanel 3/26/2008 1:01 AM SCSI
vary good sample thanks man`

But I notice one thing, if you are click on menu item and load sample1 ascx then click on submit event is fired...but...if you again click from menu and load again sample1 ascx and then click submit event will not fire...but it will fire second time when you click submit again...
How to solve this???

Thanks...

# re: Loading UserControl Dynamically in UpdatePanel 4/17/2008 2:05 AM tv izle
Hello
Ok the pageload event in the client side fires for every Thank you

# re: Loading UserControl Dynamically in UpdatePanel 5/30/2008 1:19 PM vaskar
Nice topic , it really help me a lot.
But is there any way i.e. to use javascript to load the user controls at the first time.
if possible please help me



# re: Loading UserControl Dynamically in UpdatePanel 7/2/2008 2:18 PM Faisal
its a nice article..but can you tell me how to render samplecontrol1 4-5 times in a single page? like if i click 5 times on tree view 'Load Control 1' and it will show samplecontrol1 5 times?

# re: Loading UserControl Dynamically in UpdatePanel 8/18/2008 10:04 PM Professional-Icons
Is there an easy way to dynamically load a user control without the controls (inside the user control) becoming ajaxified? All of the controls inside my user control are all updating each other on every postback. Any help would be greatly appreciated.

# re: Loading UserControl Dynamically in UpdatePanel 8/25/2008 8:48 PM Micael
For SCSI : it is due to the use of a dynamically added trigger in the Page.Load event.
You need to put the declaration of this trigger in the Page.Init if you want it to work everytime.
I had this problem before but since I do all in Page.Init it works perfectly.

# re: Loading UserControl Dynamically in UpdatePanel 9/22/2008 2:58 PM Peter
Very useful blogpost. Saved me some time... Thanks!

# re: Loading UserControl Dynamically in UpdatePanel 10/3/2008 11:08 AM Maxi
Hi SCSI

I ran into the same problem and solve it.
event handler won't register if you add your controls in page_load. add them in page_init instead.

you can see the post in my blog : maxi326.wordpress.com

# re: Loading UserControl Dynamically in UpdatePanel 10/29/2008 8:59 PM Peter
Hello!

How to do when I want a Selected Menu Item? Let say I have five User Controls. When i load the page none of them is selected from the start, how do i select a User Control that dynamicly load in on Page_Load?

Thanks!

# re: Loading UserControl Dynamically in UpdatePanel 11/11/2008 5:46 AM yen
There seems to be a bug.

If you press control2 in the menu THEN use f5 to refresh the browser you lose the page you are on but on top of that you also wont be able to load any control at all.

trying to figure out a fix for it but havent found one yet..

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: