Programmatically adding ASP.net User Control to UpdatePanel

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ChrisCicc
    New Member
    • Jun 2007
    • 5

    Programmatically adding ASP.net User Control to UpdatePanel

    Hi All, I got a real doozy here. I have read hundreds upon hundreds of forum posts and found numerous others who have replicated this problem, but have yet to find a solution. Through testing I have been able to find the cause of the problem, and will describe it here first textually and then through a code example.

    The purpose of what I am trying to do is to create a postback-free web application through the use of ASP.net AJAX UpdatePanels and User Controls. When programmaticall y adding a User Control to a web page through a normal postback everything works fine. All the controls within the user control are registered properly in the page and any update panels included in the user control also work properly. HOWEVER, if instead of using a full postback you use an UpdatePanel and a partial page update of the UpdatePanel the controls do not get registered with the page and events from them do not fire (for instance, a button click event never hits the event breakpoint).

    Because the very same user control works fine if loaded in a full postback or dynamically added from a namespace works fine, I can be relatively sure that it only is trouble when loading via a partial page update into an UpdatePanel. I load the control via the LoadConrol method and then add it to the page via a PlaceHolder control. Theoretically, adding the User Control to the PlaceHolder should register itself and it's controls and events with the page, but it does not.

    The following code sample is a UpdatePanel-free page using a user control that works, later I will show the same code with an UpdatePanel that does not.

    I think I need to figure out how to register the controls and their events with the page without going through a full page postback. Any suggestions??

    This example works as expected:
    Default.aspx:
    Code:
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:PlaceHolder ID="UCPlaceHolder" runat="server"></asp:PlaceHolder>
            </div>
        </form>    
    </body>
    </html>
    Default.aspx.cs :
    Code:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Control ctl = LoadControl("~/UserControlDemo.ascx");
            ctl.ID = "UC1";
            this.UCPlaceHolder.Controls.Add(ctl);
        }
    }
    UserControlDemo .ascx:
    Code:
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="UserControlDemo.ascx.cs" Inherits="UserControlDemo" %>
    <asp:Button ID="Button1" runat="server" Text="Display from UC" OnClick="Button1_Click" />&nbsp;<br />
    <br />
    <asp:Label ID="Content" runat="server" Text="Content"></asp:Label>
    UserControlDemo .ascx.cs:
    Code:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    public partial class UserControlDemo : System.Web.UI.UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
            Content.Text = "Content Changed.";
        }
    }
    Now, consider this variation, where instead of loading the control in the PageLoad event, you do so programmaticall y via a button Click event. This does not work as it cause a full postback which refreshes the placeholder. Viewstate does not seem to be working in this case. (uses the same user control as the previous example)

    Default.aspx:
    Code:
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Button ID="Button1" runat="server" Text="Load User Control" OnClick="Button1_Click" />&nbsp;
                <br />
                <br />
                <asp:PlaceHolder ID="UCPlaceHolder" runat="server"></asp:PlaceHolder>
            </div>
        </form>    
    </body>
    </html>
    Default.aspx.cs :
    Code:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
            Control ctl = LoadControl("~/UserControlDemo.ascx");
            ctl.ID = "UC1";
            this.UCPlaceHolder.Controls.Add(ctl);
        }
    }
    To solve this postback problem, one would naturally want to use an UpdatePanel, like the following example. However this does not work as the controls do not seem to get registered with the page, and further nesting of user controls in UpdatePanels (to create a postback free app) are no better.

    Default2.aspx:
    Code:
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
    
    <!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>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true"></asp:ScriptManager>
        <div>
            <asp:UpdatePanel ID="UpdatePanel2" runat="server">
                <ContentTemplate>
                    <asp:Button ID="Button1" runat="server" Text="Load User Control into UpdatePanel" OnClick="Button1_Click" />
                </ContentTemplate>
            </asp:UpdatePanel>
            <br />
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                <ContentTemplate>
                    <asp:PlaceHolder ID="ContentPlaceHolder" runat="server"></asp:PlaceHolder>
                </ContentTemplate>
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Button1" />
                </Triggers>
            </asp:UpdatePanel>
        </div>
        </form>
    </body>
    </html>
    Default2.aspx.c s:
    Code:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    public partial class Default2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
    
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
            Control ctl = LoadControl("~/UserControlDemo.ascx");  //loads into the page
            ctl.ID = "UC1";
            this.ContentPlaceHolder.Controls.Add(ctl); //adds to page control tree (or at least it should)
        }
    }
    I know I can use the "visible" property of my controls to toggle them on and off a page to create a flicker free experience, however, my application is a database intensive app and I don't want the page running queries against the database unless I'm absolutely sure the user wants them. Rendering a 10 forms and keeping them hidden isn't a big deal, but running 10 queries that the user never wants to see is, otherwise I'd stick to that method, its works perfectly. Any suggestions? Or requests for clarification? Any help you can provide is much appreciated...
    Last edited by Frinavale; Dec 9 '09, 03:00 PM. Reason: Thread moved to ASP.NET from .NET
  • senaka
    New Member
    • Feb 2007
    • 23

    #2
    try this.... UpdatePanel.Con trols.Add(contr ol_name) instead of this.ContentTem plate.Controls. Add(control_nam e). Because, this refers to the page as a whole and not to your update panel.

    the Visibility issue works well if your control is embedded inside a Panel... Therefore, if the panel is not visible, your controls wont get loaded.

    Regards,
    Senaka

    Comment

    • ChrisCicc
      New Member
      • Jun 2007
      • 5

      #3
      Originally posted by senaka
      try this.... UpdatePanel.Con trols.Add(contr ol_name) instead of this.ContentTem plate.Controls. Add(control_nam e). Because, this refers to the page as a whole and not to your update panel.

      the Visibility issue works well if your control is embedded inside a Panel... Therefore, if the panel is not visible, your controls wont get loaded.

      Regards,
      Senaka
      Hey Senaka,
      thanks for your suggestion. No matter which combination of Controls.Add() I use it doesn't seem to make a difference as long as the User Control is added to a UpdatePanel. The control itself will load, but none of the controls or properties or events therein are accessible.

      Ideally, I'd like to be able to keep using UpdatePanels, PlaceHolders, and User Controls to create a postback-free UI. Right now I'd have to settle for a postback on every page with only parts of the UI AJAXified.

      Comment

      • Frinavale
        Recognized Expert Expert
        • Oct 2006
        • 9749

        #4
        Originally posted by ChrisCicc
        Hey Senaka,
        thanks for your suggestion. No matter which combination of Controls.Add() I use it doesn't seem to make a difference as long as the User Control is added to a UpdatePanel. The control itself will load, but none of the controls or properties or events therein are accessible.

        Ideally, I'd like to be able to keep using UpdatePanels, PlaceHolders, and User Controls to create a postback-free UI. Right now I'd have to settle for a postback on every page with only parts of the UI AJAXified.
        I don't know if this can help you but have you thought about putting the UpdatePanel into your user control instead of adding your user control to the update panel?

        -Frinny

        Comment

        • ChrisCicc
          New Member
          • Jun 2007
          • 5

          #5
          Originally posted by Frinavale
          I don't know if this can help you but have you thought about putting the UpdatePanel into your user control instead of adding your user control to the update panel?

          -Frinny
          Hey Frinny,
          Thanks for the reply. Good suggestion, I have tried that, but it makes no difference whether the UpdatePanel is in the user control because even if it was the page wouldn't know it. It visually loads the user control, but does not programmaticall y register it's controls or events.

          -chris

          Comment

          • Frinavale
            Recognized Expert Expert
            • Oct 2006
            • 9749

            #6
            Originally posted by ChrisCicc
            Hey Frinny,
            Thanks for the reply. Good suggestion, I have tried that, but it makes no difference whether the UpdatePanel is in the user control because even if it was the page wouldn't know it. It visually loads the user control, but does not programmaticall y register it's controls or events.

            -chris
            This is an interesting problem.
            It seems to me that because you register a control with the page, and because the page is only rendered once, you might have an impossible task at hand....unless you do a postback to register the control with the page, but you don't want to do that. I believe you're going to have to re-think your system....

            I'm interested to know how you solve this problem.

            -Frinny

            Comment

            • ChrisCicc
              New Member
              • Jun 2007
              • 5

              #7
              Originally posted by Frinavale
              This is an interesting problem.
              It seems to me that because you register a control with the page, and because the page is only rendered once, you might have an impossible task at hand....unless you do a postback to register the control with the page, but you don't want to do that. I believe you're going to have to re-think your system....

              I'm interested to know how you solve this problem.

              -Frinny
              You hit the nail on the head. I can't believe that ASP.net AJAX has such a gaping hole in it, otherwise it's really an incomplete framework. Most other AJAX frameworks can do this, but I'd like to stay with the development ease of ASP.net AJAX. If I find a solution I'll pass it along!

              Comment

              • amodi
                New Member
                • Nov 2009
                • 1

                #8
                Hi ChrisCicc,
                I ran into the same problem, did you find the solution?
                Thanks.

                Comment

                • JWelch
                  New Member
                  • Dec 2009
                  • 3

                  #9
                  Any Solution?

                  I am so happy to finally find I am not the one with this problem. Did you find an appropriate solution yet? I have an update panel that loads a user control. The user control has an updatepanel containing a datalist. Outside of this updatepanel is an Add link. The Add link works great, but the "Remove" link tied to the datalist does not.

                  So - any solutions would be great to hear.

                  Many thanks!

                  Comment

                  • Frinavale
                    Recognized Expert Expert
                    • Oct 2006
                    • 9749

                    #10
                    I just looked over the code posted in the original post and I realized that the original-poster is using the LoadControl method in the PageLoad event.

                    This could be causing all of the problems. Try moving this to the Page Init event instead.



                    The ViewState contains state information about the control. If your dynamic control was a TextBox, the text that the user entered into the TextBox is loaded into the Server Side TextBox object when the ViewState is loaded for this dynamic TextBox happens.

                    Likewise, if you have a dynamic button and the user clicks the button, the button click event is detected when the ViewState is loaded for the button control.

                    If you do not instantiate your dynamic controls in the Page Init event then any events or other ViewState data will not properly be loaded and your code wont work as you expect it.

                    The crazy thing is that instantiating your dynamic controls elsewhere in the page life cycle will also work...but just not always.

                    Try this and let me know if it gets you anywhere.

                    -Frinny

                    Comment

                    • JWelch
                      New Member
                      • Dec 2009
                      • 3

                      #11
                      On Init

                      Yes, I had also seen this issue. I am using base classes for my user controls and my user controls are loading other usercontrols. Basically, we only want to load things onto the page when the user clicks for them.

                      I did find something interesting. If you register the user control on the page and then load it in via the placeholder, the events are fired just fine.

                      So the problem really is in relation to the controls being initialized fully prior to loading and using them.

                      Since we have a variety of controls we can be loading in depending on what was clicked, my end result will likely involve me setting the class property along with the control path for loading.

                      Two other important things are:
                      1) Make sure to always set an ID
                      2) Use Page.LoadContro l when loading from base classes

                      I'll let you know what the final solution ends up being after it is well tested.

                      Comment

                      • Frinavale
                        Recognized Expert Expert
                        • Oct 2006
                        • 9749

                        #12
                        Originally posted by JWelch
                        I'll let you know what the final solution ends up being after it is well tested.
                        I'm looking forward to what you end up doing.

                        -Frinny

                        Comment

                        • JWelch
                          New Member
                          • Dec 2009
                          • 3

                          #13
                          I also forgot that you can register your usercontrols in the web.config in the <controls> section. While you wouldn't want to do this for a large number of controls, it does allow all pages to access these controls when needed. So, if you have a few controls that you need to load dynamically at different points, this is a good solution. I am only doing this for the 4 that I need access to for the async postbacks.

                          Using the web.config for is also good for things like headers and footers that every page uses. Just keep in mind that this slows down the initial start of the site vs. taking this time on the pages that use the controls so you should consider these tradeoffs.

                          I hope this is of help to others,

                          Jayme

                          Comment

                          • quentez
                            New Member
                            • Feb 2010
                            • 1

                            #14
                            Two other important things are:
                            1) Make sure to always set an ID
                            2) Use Page.LoadContro l when loading from base classes
                            JWelch you saved my day !! I've been on this issue for 3 days now and this solved everything. I LOVE you man !

                            Comment

                            • Ghayas
                              New Member
                              • Apr 2010
                              • 6

                              #15
                              Hi JWelch ,
                              i have a vb file lets say abc.vb placed under app_code
                              i have defined <add tagPrefix="Cust om" namespace="abc" />
                              in webconfig file under controls tag,
                              when i use it in my page its show an error that webconfig file is missing
                              what m i doing wrong,
                              thanks

                              Comment

                              Working...