UpdatePanel – In Depth


For all the ASP.Net AJAX (formerly "Atlas") lovers out there, I decided to put together some information (I consider useful) in this blog - this is also for folks who might have missed my webcast on the topic which was delivered on 10/26.


The Partial Page Rendering feature has been one of the most popular feature in the ASP.Net AJAX framework. The feature is built using 3 components - the ScriptManager and the UpdatePanel on the server and the PageRequestManager object on the client.


 The ScriptManager controls the partial rendering behavior by the 'EnablePartialRendering' property, when set to true the page is enabled for async post-backs and any UpdatePanel controls on the page can be updated as a result of this post-back. It also provides for global properties such as AsyncPostBackTimeout and AllowCustomErrorsRedirect which govern the handling of the page in certain common scenarios. The AllowPostBackTimeout causes a timeout error to return to the client if the async post-back took longer than the timeout defined. The 'AJAX' experience is all about providing a rich, integrated experience to the users - consider a wizard where user fills in certain information, now to provide the page with no flicker capability and also to reduce the amount of data being sent over the wire, the page developer wraps the wizard with an UpdatePanel, now let's assume that while a user is going through the wizard adding information they encounter a server error on the fifth step. If the custom errors were turned ON, redirection would happen to the customer error page - if the user hit 'Back' in the browser they would be directed to the first step in the wizard as the async post-back do not add to browser history. Thus you can set the 'AllowCustomErrorRedirects' property to false to prevent redirection and send the error to the client where it can be handled by the application. The ScriptManager control also provides for script registration methods which allow for scripts to be tracked based on the control which rendered these


   public void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags)
   public void RegisterClientScriptInclude(Control control, Type type, string key, string url)
   public void RegisterClientScriptResource(Control control, Type type, string resourceName)
   public void RegisterHiddenField(Control control, string HiddenFieldName, string HiddenFieldValue) 
   public void RegisterOnSubmitStatement(Control control, Type type, string key, string script)
     public void RegisterStartUpScript(Control control, Type type, string key, string script, bool addScriptTags) 

As can be noticed hte script registration methods take the control instance as a parameter which helps in associating controls with the script they registered and send these scripts to the client if the control was rendered during an async post-back.


The ScriptManager also allows for sending additional data to the client during async poast-back [RegisterDataItem(Control, string)] and registering dispose functions which are called when a control/component is disposed on the client during async post-back as new content replaces the old. The ScriptManager also provides the functionality to fall back to regular post-backs if a browser does not support the expected version of w3c DomVersion, ecmaScript and xmlhttp. This can also be controlled by the user via the SupportsPartialRendering property or by the browser capapbilities mentioned above.


 The object on the client which handles the async post-back is the PageRequestManager - this can be found in the webforms.js that ship with ASP.Net AJAX 1.0. When a user interacts with a page to cause a post-back and the control that caused the post-back is either a child of an UpdatePnael on the page or is registered as an async post-back control then this will cause an async post-back. The PageRequestManager uses the client-side Networking objects to set up a request which is sent to the server via xmlhttp. The PageRequestManager then waits for a callback from the server and this contains the response generated on the server. The PageRequestManager parses the response from the server and then raises the remaining lifecycle of events and ultimately updates the DOM on the client to reflect the rendering updates from the async post-back. The following image displays the client-side events raised during an async post-back



Here are some more details regarding the events


initializeRequest event: can be used for canceling a new async post-back request if one is on-going. Also the post-back source can be evaluated to do any additional work


public class InitializeRequestEventArgs : CancelEventArgs {


bool cancel { get; set; };


DOMElement postBackElement { get; };


Sys.Net.WebRequest request {get; };


}


 


beginRequest event: can be used for handling UpdateProgress, start showing progress in this event and hide it in the endRequest event


public class BeginRequestEventArgs : EventArgs {


Sys.Net.WebRequest request {get; };


DOMElement postBackElement { get; };


}


 


pageLoading event: can be used to do additional handling for the panels being updated or deleted. Hook-up for doing clean up logic. Also additional data sent from the server can be inspected for doing customizations.


public class PageLoadingEventArgs : EventArgs {


Dictionary dataItems { get; };


DOMElement[] panelsDeleting { get; };


DOMElement[] panelsUpdating { get; };


}


 


pageLoaded event: similar to pageLoading, though in this case you have knowledge on any additional UpdatePanels that were created due to the async post-back


public class PageLoadedEventArgs : EventArgs {


Dictionary dataItems { get; };


DOMElement[] panelsCreated { get; };


DOMElement[] panelsUpdated { get; };


}


 


endRequest event: Can be used to customize error handling, and also to process additional data form the server. Finally endRequest can be used to manage the UpdateProgress hiding.


public class EndRequestEventArgs : EventArgs {


Dictionary dataItems { get; };


Error error { get; };


bool errorHandled { get; set; };


Sys.Net.WebRequestExecutor response {get; };


}


The following sample attaching to the events


<span ID="PRM_Events" >PageRequestManagerEvents:</span>
<script type="text/javascript" >
  function beginRequestEventHandler(sender, arg) 
    {
      document.getElementById("PRM_Events").innerHTML = "[beginRequest]";
    }

 function endRequestEventHandler(sender, arg)
  {
    document.getElementById("PRM_Events").innerHTML += "[endRequest][endRequestHasError:";
    var errorObject = arg.get_error();
    if(errorObject != null)
    {
      document.getElementById("PRM_Events").innerHTML += "true]";
      arg.set_errorHandled(true);
    }
    else
    {
      document.getElementById("PRM_Events").innerHTML += "false]";
    }
  }
        
  function printArray(name, arr)
  {
    var panels = name + "=" + arr.length;
    if(arr.length > 0)
    {
      panels += "(";
      for(var i = 0; i < arr.length; i++)
      {
        panels += arr[i].id + ",";
      }
      panels = panels.substring(0, panels.length - 1);
      panels += ")";
    }
    return panels;
  }
            
  function pageLoadingEventHandler(sender, arg) 
  {        
    var updatedPanels = printArray("PanelsUpdating", arg.get_panelsUpdating());
    var deletedPanels = printArray("PanelsDeleting", arg.get_panelsDeleting());
    var message = "[pageLoading:" + updatedPanels + ";" + deletedPanels + "]";
            
    document.getElementById("PRM_Events").innerHTML += message;
  }
            
  function pageLoadedEventHandler(sender, arg) 
  {
    var updatedPanels = printArray("updatedPanels", arg.get_panelsUpdated());
    var createdPanels = printArray("createdPanels", arg.get_panelsCreated());
        
    var message = "[pageLoaded:" + updatedPanels + ";" + createdPanels + "]";
            
    document.getElementById("PRM_Events").innerHTML += message;
  }
    
  Sys.WebForms.PageRequestManager.instance.add_beginRequest(beginRequestEventHandler);
  Sys.WebForms.PageRequestManager.instance.add_pageLoading(pageLoadingEventHandler);
  Sys.WebForms.PageRequestManager.instance.add_pageLoaded(pageLoadedEventHandler);
  Sys.WebForms.PageRequestManager.instance.add_endRequest(endRequestEventHandler);
   </script>
 

Finally, lets look at the updatePanel control itself. The UpdatePanel marks regions of the page which are rendered during an async post-back. The UpdatePanels that are updating can be further filtered by setting the UpdateMode property on the UpdatePanel to 'Conditional'. The default is 'Always'. When set to conditional the UpatePanel updates if any control within it causes a post-back or a trigger for the update panel causes a post-back. In the sample below clicking on 'Button1' causes UP1 to be updated. The 'ControlID' in a trigger can point to a control which implement either IPostBackEventHandler, or IPostBackDataHandler or INamingContainer - if it points to a control that implements INamingContainer then any post-back controls inside this control will act as triggers for the UpdatePanel.


<asp:button runat="server" id="Button1" Text="Update" />

<asp:UpdatePanel


    ID="UP1"


    UpdateMode="Conditional"


    runat="server"


> 


    <ContentTemplate>…</ContentTemplate>


    <Triggers>


        <asp:AsyncPostbackTrigger


            ControlID="Button1"


        />


     </Triggers>


</asp:UpdatePanel>


In closing, I am attaching some demo samples for the webcast (most of which were written by one of our devs Eilon - Thanks Eilon) and also the slidedeck with this post. Hopefully you find this useful.


 Please post any feedback you might have and I will try my best to respond.


 Thanks,


Kashif 


 


 

PanelProgress.zip

Comments (9)
  1. Javier Luna says:

    Great post!

    But I have received this error message:

    “RegisterDataItem can only be called during an async postback”

    I have a DataList with ImageButton (CauseValidation=”False”) in an UpdatePanel. The PopupControlExtender show/hide the panel.

    The DataList’s ItemCommand event just call to PopupControlExtender’s Commit method.

  2. kalam says:

    Javier,

    Great that you found the post useful. Can you share more details around where your code calls into RegisterDataItem? It is true that RegisterDataitem can only be called during an async postback as the name-value collection populated by this is made available in the client events raised as part of an async postback. Thus if RDI is called outside of async postback then the given error will be raised.

    Thanks,

    Kashif

  3. Ryan says:

    Do you know how I can call out to another update panel and update it if I don’t know what its name is going to be. I am using multiple update panels on a page inside DNN. When a user adds items to a cart I need to be able to refresh the cart summary total price in another update panel on the page but only after my server side code has run. I can fire a dopostback client side to another update panel but this event fires before my server side events execute. I need to do this after. How can I first find the update panel I need then call its update. Do I have to inject the client side script into the page after I do the server side code. Seems like a kluge to me!

  4. reminvestor says:

    Do you know how I can call out to another update panel and update it if I don’t know what its name is going to be. I am using multiple update panels on a page inside DNN. When a user adds items to a cart I need to be able to refresh the cart summary total price in another update panel on the page but only after my server side code has run. I can fire a dopostback client side to another update panel but this event fires before my server side events execute. I need to do this after. How can I first find the update panel I need then call its update. Do I have to inject the client side script into the page after I do the server side code. Seems like a kluge to me!

  5. reminvestor says:

    Do you know how I can call out to another update panel and update it if I don’t know what its name is going to be. I am using multiple update panels on a page inside DNN. When a user adds items to a cart I need to be able to refresh the cart summary total price in another update panel on the page but only after my server side code has run. I can fire a dopostback client side to another update panel but this event fires before my server side events execute. I need to do this after. How can I first find the update panel I need then call its update. Do I have to inject the client side script into the page after I do the server side code. Seems like a kluge to me!

    ScriptManager.RegisterClientScriptBlock(Me, [GetType], "key", "__doPostBack(‘<%= CartSummary.ClientID %>’, ”);", True)

  6. reminvestor says:

    Do you know how I can call out to another update panel and update it if I don’t know what its name is going to be. I am using two update panels on a page inside DNN Modules. When a user adds items to a cart I need to be able to refresh the cart summary total price in another update panel on the page but only after my server side code has run. Since the panels are not nested I can’t use updatemode. I can fire a dopostback client side to another update panel but the client side event fires before my server side events execute. I need to do this after. How can I first find the update panel I need then call its update. Do I have to inject the client side script into the page after I do the server side code. Seems like a kluge to me!

    I tried doing this in my server side code after I add items to cart but it didn’t work.

    ScriptManager.RegisterClientScriptBlock(Me, [GetType], "key", "__doPostBack(‘<%= CartSummary.ClientID %>’, ”);", True)

  7. Thomas Kopp says:

    Hi Kashif;

    I’m using an update panel around a Wizard control as you mentioned.  I’ve also got panels inside wizard steps that are triggered by various controls in the same wizard step.  However, some controls on the wizard step need to cause the entire wizard to refresh.  The problem I’m getting into is that I have to set the UpdatePanel around the Wizard to ChildrenAsTriggers="false" to prevent the nested update panels from causing the whole wizard to refresh.  But when I try to set the controls on the wizard step as triggers (in the aspx code or programmatically), the UpdatePanel around the Wizard cannot find them.

    Thus:

        <asp:UpdatePanel ID="Page1_Runstart_ctl_upRunStart" runat="server"

         ChildrenAsTriggers="false" UpdateMode="conditional">

       <Triggers>

           <asp:AsyncPostBackTrigger ControlID="Page1_Runstart_ctl_ddlTypeOfService" />

           <asp:AsyncPostBackTrigger ControlID="Page1_Runstart_ctl_ddlCallOutcome" />

       </Triggers>

    .

    .

    .

    [Wizard]

    .

    .

    .

           </ContentTemplate>

       </asp:UpdatePanel>

    The controls set as triggers are in the first WizardStep.  This gives me the error:

    A control with ID ‘Page1_Runstart_ctl_ddlTypeOfService’ could not be found for the trigger in UpdatePanel ‘Wizard_ctl_upWizard’.

    This is driving me nuts.  Any ideas?  Thanks!

  8. John Grant says:

    Hi,

    I’ve been working on a patient registration website wizard with my current employer. The website makes use of an asp.net 2.0 wizard control wrapped inside an update panel. However, I am running into problems with partial page updates. On some steps the partial rendering works perfectly. On other steps or when the back button is hit, instead of just a partial page update the whole page flickers and is updated. It appears to be an entire page update.

    I’m also using master and content pages. My master page contains my script manager, defined at the very top of the page just inside the Form tag which is just inside the Body tag.Reading down the page, inside the form tag, there is a container Div for formating, then a header Div, a content Div, and finally a footer Div.

    The content Div contains an UpdatePanel tag which contains the ContentPlaceHolder. Inside the content Page is my wizard.

    Why is the partial page update only working on some steps and not all of them? Any help is greatly appreciated. Thanks!

    johnny g.

  9. Curious says:

    Do you how to check if async postback timeout for UpdatePanel?

Comments are closed.

Skip to main content