UpdatePanels - Usage Tips...
The Microoft.Ajax UpdatePanel is the control that immediately adds a 'ajaxified' enviroment. Its simple to use and has a ton of neat features. However, it can also be a control that wrecks havoc when it comes to troubleshooting. This article will hopefully clear up some misconceptions on what you can do and where. Feel free to leave some comments if you would like to add something additional.
Troubleshooting:
Check conditions under various browser settings:
In IE under Tools -> Internet Options you have various settings for controlling how IE behaves when requesting content from a server.
Always: Every script, resource, etc will be downloaded all the time. This can be misleading to those using Fiddler to track what is being requested. Additionally, you need to verify the behavior works as advertised in the next mode I will mention. In the traditional Dev enviroment we set IE to this mode because it assures us that we are not working with a cached copy. (And we have all done that - made changes and kept trying to troubleshoot why the scenario isn't changing when we know it should - particulary with CSS files, script files etc..)
Automatically: Development wise - this mode will cause all kinds of issues because it caches requests and if it can pull content from the browser cache - it will. However, you still need to verify your site works in this mode as this will be the setting most website visitors will have their browsers set to.
UpdatePanel operates in two modes: Always and Conditional.
This mode setting inidcates how content is handled within an update panel.
Always: All of the viewstate, is sent back to the server in terms of a "full postback" for everything in the UpdatePanel. If you are having problems using Conditional - using this setting does provide a work around. In some cases you may want to use this mode if back-end code if - the response sent back requires interaction with other controls. Example, you perform a check to see if a checkbox is enabled upon a dropdownlist being selected, prior to setting a value of a label. In this manner the mode "Always" allows you to program in your traditional manner with little concern of trying to figure out what type of asynchronous request is being sent.
Conditional: This is asynchronous enablement. Pure and simple and the only time you will see the ScriptManagerControl when it is managing a update panel sets its IsInAsyncPostBack to true. If you check for this property value you can do some custom processing if you like.
Additional Note: You'll find that if you are using multiple ToolKit controls in Conditional Mode, the errors will ambigious or, what will happen if a control does not update properly the content will remain displayed but your action will not actually occur. Usually, if you are tracking exceptions - this will be myControl = null or myControl is not set to reference of an object. Setting the mode to Always will typically generate an actual message.
Also, if you are troubleshooting - don't be shy about closing out of all instances of your browsers and do an IISRESET. You'll find that more accurate errors will be displayed and I have personally seen this happen time and time again in my own troubleshooting of issues....Don't ask me why but I think the js scripts get stored in memory and are not always reloaded. Remember these scripts handle DOM and intercept and react on the browser - hiding server events as they are intercepted. These are merely my experiences and sharing to hopefully save you some frustration.
I am going to forgo the basics of the UpdatePanel and instead address issues that occur in my development and some of which have been addressed in various blogs and forum posts by others. Please note however; that this is my own personal interpretation of how these controls work and in no way meant to be anything 'official'. I write these articles as a learning process for myself and hopefully the information contain is accurate but not garunteed - use at your own risk...
Use of <Triggers>
Because it is available and the name itself implies "I can't get something to work so got to use it" - is wrong. By default every control in a UpdatePanel will asynchronously postback as all of the controls are AUTOMATICALLY added to the UpdatePanel's child controls collection. So, Triggers should actually only be used primarily in only two scenarios.
Scenario 1: You have controls in a UpdatePanel that need to be reacted upon by a control outside of the UpdatePanel. For instance you have a UpdatePanel with a Gridview and it allows for editing of records. The DataSource is cached or only loaded when a Page.IsPostBack is false. You have a "Refresh Button" outside of the UpdatePanel that needs to be used to refresh the GridView data.
Scenario 2: You set the Update Panel's ChildrenAsTriggers to FALSE. In this scenario you will have to add <Triggers> that point to controls within the UpdatePanel - otherwise the control will not postback and refresh in the UpdatePanel as the controls child collection will be null.
Bug: Use of <UpdateProgress>
If you have a simple page or control and the UpdatePanel doesn't contain controls that use templates or repeaters (Which includes, Gridviews, Datagrids, DropDownLists etc) you might not be able to get the update panel to update. Sounds bizarre but with this Beta release - once the designers went to the static prototype methods, something broke. It worked fine in the Atlas version but the new Beta will cause some unpredicatable behaviors. The most common sympton will be where you have multiple <UpdatePanels> in your page or control and one <UpdatePanel> invokes an update in another <UpdatePanel>. If the <UpdateProgress> and corresponding <AlwaysVisible> control is in the originating <UpdatePanel> it will break your app. The fix is - to move the target <UpdatePanel> to the top of all the others, and insert before the closing </ContentTemplate> the <UpdateProgress> and corresponding <AlwaysVisible> control (as well as target panel).
Ironically it may also fix one of your issues with databound controls in your 'main' <UpdatePanel> in that now databound controls that remain hidden when say a ModalPopup is displayed - will now work as they should using the steps listed previously. The problem occurs in both FireFox and Internet Explorer when a modal's Show(), Hide() are invoked in codebehind.
Advanced:
You can speed up some the 'delay' with Internet Explorer by editing the Toolkit's ModalPopupBehavior.js:
show : function() {
AjaxControlToolkit.ModalPopupBehavior.callBaseMethod(this, 'populate');
this._attachPopup();
this._backgroundElement.style.display = '';
this._foregroundElement.style.display = '';
// Disable TAB
this.disableTab();
this._layout();
// On pages that don't need scrollbars, Firefox and Safari act like
// one or both are present the first time the layout code runs which
// obviously leads to display issues - run the layout code a second
// time to work around this problem
this._layout();
// Original
// this._layout();
//
//Jody's Change
//
//If not required for IE then skip it if IE is detected - why do something twice when once is enough?
if (!(Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7))
{
this._layout();
}
//End Change
}
Remember to recompile.
Remember to either close your browser or do Tools -> Delete Files otherwise the change will not be evident
It speeds it up slighty - kinda a nit picky observation on my behalf but does make a difference.
Dangerous Requests!
if you get a message as such:
Server Error in '/SitesEasyTest' Application.
A potentially dangerous Request.Form value was detected from the client (ctl00$ctl00$ctl00$.....="...
I will bet that you are dynamically loading controls in a update panel. Remember - if you have a placeholder and loading dynamic controls, in a ajax enviroment you have to clear the controls before you can 're-add' them. Keep in mind while you are regenerating the page on the server side - the clients page is just waiting for an update and that is it..
Your next question is "But I am clearing the controls so what happens to control state and viewstate?" . As long as you always assign the same control ID when you rebuild the page on the server side - then magically al previous viewstate and control state is restored! Sounds counter-intuitive - but it is how it works.
If you do not specify the control's ID a new control will be APPENDED on the client side - without the viewstate info and the previous control will be left at the state last known on the client side (as it was never changed)...
Here is sample code to illustrate the proper way to do this:
override protected void BindModal()
{
try
{
//child control heirachy....
ctlLoad.Controls.Clear();
ctlToAdd = new ConfigDocMain(); //This is my control to load
ctlToAdd.ID = "ctlToAdd1"; //always the same
ctlLoad.Controls.Add(ctlToAdd);
ctlLoad.DataBind(); //Must Databind
EnsureChildControls();
//MUST CALL THE UPDATE PANEL's UPDATE() otherwise
//Assertion Error as viewstate is dirty at this point.
//UpdatePanelModal.Update();
if (UpdatePanelModal.UpdateMode.ToString() == "Conditional")
{
UpdatePanelModal.Update();
}
}
}
Note that if your dynamic control has templated features or repeators as of the original BETA release its suggested to do this on Page_Load.
If the ctlLoad.Controls.Clear() was not called in the above code example - this would of been your error:
Multiple controls with the same ID 'ctlToAdd1' were found. FindControl requires that controls have unique IDs.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
However, you do not always have to call it. Anytime the UpdatePanel has a child control that triggers a asynch request it automatically runs the Update(). In Atlas it was a requirement to do as viewstate would get muddied. In ajax Beta, I find it does whether well with out it being called in code behind in most scenarios (Like a gridview page event - I never run the update - it just does it on its own. However, loading dynamic controls - I usually do call it although I am still experiementg when I need to).
UpdatePanelModal.Update();
You only need to call this function if you are forcing an update and the Update Panel's mode != "Always" hence in the code example above - we check to see if the mode is Conditional before calling the update. Update() also may only be called if the ScriptManagers is set for enable partial renders (which is true by default so you do not have to set that declaratively anymore. In Atlas - the default was false, in ajax Beta the default is true.
About Targets.
Most all ajax extended controls require a target of some sort. Take for instance this code example:
<ajax:UpdatePanel ID="UpdatePanelModal" UpdateMode="Conditional" RenderMode="Inline" runat="server" >
<ContentTemplate>
<asp:Panel ID="pnlLoading" runat="server" CssClass="pnlLoading" Visible="true" >
<ajax:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<div style="border:2px solid #0099FF; background-color:#EFEFEF; padding:10px; width:200px; height:20px;">
<img id="updateImage" src="" alt="missing image" runat="server" /> please waite...
</div>
</ProgressTemplate>
</ajax:UpdateProgress>
</asp:Panel>
<ajax:AlwaysVisibleControlExtender ID="AlwaysVisibleControlExtender1" runat="server"
TargetControlID="pnlLoading"
VerticalSide="top"
HorizontalSide="left"
VerticalOffset="10"
HorizontalOffset="10"
ScrollEffectDuration=".1" />
</ContentTemplate>
</ajax:UpdatePanel>
Did you spot the bad code? Visible="true" in the pnlLoading control. Don't even bother setting this value. For one, I know particularly in where a ModalPopup is being used - the progress control will never launch and a few other issues will occur. The reason being that the ModalPopup when it catalogs the dom hides any control with Visible set... and will not treat it as a extender control. It can also cause some other bizzare issues as well.
I'll probbly write more on some of the other subjects later - but hopefully, this entry of more interesting than my typical "it doesn't work" entries..
New Comments to this post are disabled