Archive for December, 2009

December 30th 2009

Fixing the UpdatePanelAnimationExtender bug when using multiple updatepanels

Recently I came across an annoying bug in the AjaxControlToolkit’s UpdatePanelAnimationExtender control. We had a page with multiple update panels, each with their own UpdatepanelAnimationExtender. When an asynchronous postback occurred, all the “OnUpdating” animations fired, but when the asynchronous postback completed, only the updatepanels that were refreshed by the postback ran their “OnUpdated” animations”.

Here’s my example page with two update panels:
Multiple UpdatePanels Each With An UpdatePanelAnimationExtender

During asynchronous postback, both update panels are faded out:
Asynchronous postback executing, all UpdatePanels are faded out

After the asynchronous postback completes, only the update panel refreshed by the postback fades in:
Asynchronous postback is complete and one UpdatePanel is refreshed, the other still running the OnUpdating animation

When an asynchronous postback is executed, the client doesn’t know what update panels will be refreshed (this is determined by the server dynamically), so all the UpdatePanelAnimationExtenders play their OnUpdating animations. The extender javascript is as follows:

_partialUpdateBeginRequest : function(sender, beginRequestEventArgs) {
	/// <summary>
	/// Method that will be called when a partial update (via an UpdatePanel) begins,
	/// if registerPartialUpdateEvents() has been called.
	/// </summary>
	/// <param name="sender" type="Object">
	/// Sender
	/// </param>
	/// <param name="beginRequestEventArgs" type="Sys.WebForms.BeginRequestEventArgs">
	/// Event arguments
	/// </param>
	AjaxControlToolkit.Animation.UpdatePanelAnimationBehavior.callBaseMethod(this, '_partialUpdateBeginRequest', [sender, beginRequestEventArgs]);

	if (!this._postBackPending) {
			this._postBackPending = true;
			this._onUpdated.quit();
			this._onUpdating.play();
	}
},

When the asynchronous postback completes, however, the behavior only selectively plays the OnUpdated animation if it’s target update panel has been refreshed:

 _pageLoaded : function(sender, args) {
	/// <summary>
	/// Method that will be called when a partial update (via an UpdatePanel) finishes
	/// </summary>
	/// <param name="sender" type="Object">
	/// Sender
	/// </param>
	/// <param name="args" type="Sys.WebForms.PageLoadedEventArgs">
	/// Event arguments
	/// </param>

	if (this._postBackPending) {
			this._postBackPending = false;

			var element = this.get_element();
			var panels = args.get_panelsUpdated();
			for (var i = 0; i < panels.length; i++) {
					if (panels[i].parentNode == element) {
							this._onUpdating.quit();
							this._onUpdated.play();
							break;
					}
			}
	}
},

The “fix” is to stop the OnUpdating animation and play the OnUpdated animation whenever the asynchronous postback completes. We can do this by creating an extender to inherit from UpdatePanelAnimationExtender and “override” the _pageLoaded method to:

	_pageLoaded: function(sender, args) {
		//avoid base call and just cancel animation. this appears to be a design limitation with multiple update panels and multiple instances of update panel animation
		if (this._postBackPending) {
			this._postBackPending = false;
			this._onUpdating.quit();
			this._onUpdated.play();
		}
	}

A sample reproducing the problem and demonstrating the work around can be found here.

3 Comments »