Welcome to ESRI Blogs

Creating a utility library (Part I): Simplify working with callback results

Morten Nielsen, a developer on the .NET Web ADF Team, contributed this series:

This post is the first in a series on creating a set of reusable helper methods that tries to make some of the common developer tasks when working with the .NET Web ADF easier.

The AJAX behavior of the .NET Web ADF has been built on top of the ASP.NET Callback Framework. The framework allows us to do a call from the browser to a server-side web control carrying a string as argument, perform some processing on the server based on this argument, and then return a new string to a javascript method on the client. The argument string coming from the browser could for instance be a key/value pair separated by ampersands, but can technically be anything you want, for instance a JSON formatted object that you later deserialize on the server.

Each web control has its own client-side method that can be executed to do the callback to the server-side instance of the control. The Web ADF’s web controls all have a ‘CallbackFunctionString’ property that returns the javascript method needed to do this callback to server.

Most of the Web ADF’s web controls use the ‘CallbackResult’ type to specify what we want to send back to the client. The Callback Result basically consists of a control id if applicable, an argument type and a set of parameters. The ‘ToString()’ method on the ‘CallbackResultCollection’ serializes this to a return string that the client-side method ‘processCallbackResults’ knows how to parse.

An important thing to remember here is that the control that received the callback is the one responsible for returning all the callback results. If you for instance use the CallbackButton to call back to the server page, make some changes to the map, refresh the Table of Contents, etc, you are responsible for picking up all the callback results from the various controls that you changed and return them though the CallbackButton’s CallbackResults collection. The way this usually is done is by copying the callback results from all other modified controls in the ‘GetCallbackResults’ method, or in the case of the CallbackButton in its click handler method. Example:

CallbackButton1.CallbackResults.CopyFrom(Map1.CallbackResults);
CallbackButton1.CallbackResults.CopyFrom(Toc1.CallbackResults);
CallbackButton1.CallbackResults.CopyFrom(TaskResults1.CallbackResults);

Where this can get tricky is that you might not realize that certain controls contain callback results. For instance if you add a new ResourceItem to the MapResourceManager, that Map will contain new CallbackResults, because it automatically listens for the ResourceItemAdded event.

Since it is possible to figure out what control did the callback, and also search for all controls that contain results, why not create a small utility method that does this search and copy them over for you? This way you just do a simple call to a static method instead of doing all the copying.

The first step is finding the control that performed the callback. The page request will contain the unique ID of the control stored in the parameter ‘__CALLBACKID’, and we can use the UniqueID to search for the control in the page:

public static Control GetCallingControl()
{
HttpContext context = HttpContext.Current;
if (context == null) return null;
Page page = context.CurrentHandler as Page;
if (page == null) return null;
else if (page.IsCallback)
{
string controlid = context.Request.Params["__CALLBACKID"];
Control c = page.FindControl(controlid);
return c;
}
else return null; //Not an asyncronous request
}

The next step is to search for all controls in the page that contain callback results. We do this by doing a recursive search through the page tree to find any control that inherits from ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl or ESRI.ArcGIS.ADF.Web.UI.WebControls.CompositeControl and copy the CallbackResults. The recursive search will clear out any CallbackResults that have been copied over, so you don’t risk copying the same results if you do this search more than once:

/// <summary>
/// Searches for and moves all <see cref="CallbackResults"/> to the
/// calling control's <see cref="CallbackResultCollection"/>.
/// Note that callbackresults on all other controls will be cleared out.
/// </summary>
/// <param name="page">Page where the asyncronous call originated.</param>
public static void AutoMoveCallbackResults()
{
Control callingControl = GetCallingControl();
if (callingControl == null)
return;
CallbackResultCollection results = null;
if (callingControl is WebControl)
{
results = (callingControl as WebControl).CallbackResults;
}
else if (callingControl is CompositeControl)
{
results = (callingControl as CompositeControl).CallbackResults;
}
else return;

autoMoveCallbackresultsRecursive(callingControl.Page.Controls, results, callingControl);
}

private static void autoMoveCallbackresultsRecursive(ControlCollection controls, CallbackResultCollection results, Control callingControl)
{
foreach (Control control in controls)
{
if (control is WebControl && callingControl != control)
{
CallbackResultCollection controlresults = (control as WebControl).CallbackResults;
results.CopyFrom(controlresults);
controlresults.Clear();
}
else if (control is CompositeControl && callingControl != control)
{
CallbackResultCollection controlresults = (control as CompositeControl).CallbackResults;
results.CopyFrom(controlresults);
controlresults.Clear();
}
if (control.Controls.Count > 0)
{
autoMoveCallbackresultsRecursive(control.Controls, results, callingControl);
}
}
}

All you need to do now is call AutoMoveCallbackResults after doing processing and all controls in the page that contains callbackresults will automatically be copied to the calling control’s callbackresult collection:

protected void CallbackButton1_Clicked(object sender, EventArgs args)
{
//Do your processing and generate callback results...
//...

WebADF.Utilities.Callbacks.AutoMoveCallbackResults();
}

You can download the code below. We also included some static helper methods for creating some of the standard callback results. Example:

WebADF.Utilities.Callbacks.CreateJavaScript("alert('Hello World');");
WebADF.Utilities.Callbacks.CreateSetInnerContent(this, "This is the inner content of this control");
WebADF.Utilities.Callbacks.CreateSetImageSource(myImage, "http://www.mydomain.com/images/picture.jpg");

Download the Web ADF Utility Class

Update: The utility library has since been updated to support 9.3 partial postbacks, and can be found in the Code Gallery. Furthermore, the static CallbackResult helper methods mentioned above are now available directly off the CallbackResult class.

Published Friday, February 22, 2008 10:38 AM by sterlingdq
Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
required 
(required)