Developing applications using the Web ADF - Working with AJAX capabilities of the Web ADF  

Working with CallbackResults 


The Web ADF contains a framework to manage the synchronization of server-client content in an asynchronous (AJAX) environment. This framework, termed the "callback results framework", consists of server-side classes and control properties and client-side Web ADF JavaScript logic. During user interaction with a Web application, the state of a Web ADF control and other content on the server will often change. Web ADF controls communicate changes in their state on the server with Web ADF controls in the browser via callback results. A "callback result" is a Web ADF specific, JSON (JavaScript Object Notation) formatted string generated on the server, often by Web ADF controls.  Custom callback results can also be created using the Web ADF CallbackResult class. All Web ADF controls have a CallbackResults property which references a collection of CallbackResult instances in a Web ADF CallbackResultCollection. Collections of callback results can be managed using the CallbackResultCollection class, which means you can add, remove and convert the entire collection to a string. Web ADF callback results are explicitly designed to be processed by the Web ADF JavaScript function ESRI.ADF.System.processCallbackResult(). Some Web controls also maintain their own processCallbackResult() function for control specific processing of callback results. In essence, the Web ADF’s callback results framework makes it easier for you, the developer, to use managed server-side classes to modify both Web ADF and non-Web ADF content in the client browser. The following diagram highlights the components of the callback results framework on the client and server.



Web ADF controls will always use callback results to update client-side content in the browser, regardless of whether you explicitly create or manage them. For example, when calling the Zoom method on a Map control, the Map control will generate a callback result. The following diagram illustrates the initial Web request which calls the Zoom() method on the Map control (server-side), then the Map control packages callback results in the Web response.  The Map control is a script control, thus it is represented on the client as a JavaScript object and on the server as a .NET Server control.





Important note: Although the technique for packaging callback results will differ depending on the AJAX pattern you choose for your page (callback versus partial postback ), callback result content and processing callback results by Web ADF JavaScript on the client will remain the same.

If a Web ADF control initiates a Web request, it will automatically package its callback results in a Web response. In some cases, a developer may want to change or interact with other controls or elements in the page besides the Web ADF control that initiated the request. This may include both Web ADF and non-Web ADF content. To use the Web ADF callback results framework to update client content, a developer must package custom messages in a CallbackResult class and make sure it is processed on the client by the Web ADF JavaScript processCallbackResult() function.

For Web ADF content, there are a number of inherent relationships between Web ADF controls where callback results are copied to the Web ADF control that packages the callback results for the response (see the section on internal callback result creation below for more details). If the Web ADF control you want to change is not covered by a pre-defined relationship, you must explicitly manage its callback results. This means you must copy the callback results for the Web ADF control you changed (via the CallbackResults property) into the callback results collection of the Web ADF control responsible for generating the callback results in the Web response. The code and diagrams below provide an example where the Web ADF Map control initiates a request and packages callback results in a response and the Toc control needs to be refreshed to reflect changes in the state of the map (e.g. a new map resource item was added). The Toc's callback results are copied to the Map’s callback results collection via the CopyFrom() method. The diagram shows the actual callback results being combined and returned in the response and provides a brief view of the underlying format of a CallbackResult and CallbackResultCollection.

CallbackResults example code

[C#]

... <new map resource item added>
Toc1.Refresh();
Map1.CallbackResults.CopyFrom(Toc1.CallbackResults);


CallbackResults process



Actual CallbackResult string content





The ability to manage callback results within and between Web ADF controls hinges on the capabilities of a CallbackResultsCollection. The CallbackResultCollection class provides a convenient means for managing multiple CallbackResult objects. While each Web ADF control maintains a CallbackResultCollection (accessible via the CallbackResults property) you can also create a CallbackResultCollection for your own use. The following table lists a number of methods on a CallbackResultCollection object you may find beneficial: 

CallbackResultCollection Method Name Description
Add Used to add individual CallbackResult instances to a collection. Often useful when creating custom CallbackResult instances and adding them to the existing callback collection for a Web ADF control.
CopyFrom Used to copy an entire CallbackResultCollection to another collection. Often useful when you need to update a Web ADF control whose callback results are not automatically included in a response. Merely copy its callback results into the Web ADF control responsible for generating the callback results in a response.
ToString Used to convert a CallbackResultCollection into a string with the appropriate formatting for the processCallbackResult() function to parse and utilize its content. Often useful in cases where the control responsible for generating the callback results for a response is not a Web ADF control -or- the AJAX pattern requires callback results be explicitly packaged as a string .  


So far, this section has discussed existing CallbackResults and CallbackResultCollections associated with Web ADF controls. In many cases, you may want to work with non-Web ADF content in your page. For non-Web ADF content, you have a choice of using AJAX pattern specific techniques or the Web ADF callback result framework. For example, to update a ListBox or GridView using the partial postback pattern, you can use an UpdatePanel. If you do choose to leverage the callback result framework, a custom CallbackResult object should suit your needs. The next section focuses solely on custom CallbackResult objects and capabilities.  


Custom callback results

The CallbackResult class defines a set of arguments that enable you to work with almost any html content in the page by utilizing client-side technologies and the browser DOM (document object model) to locate and interact with elements in the page. For example, custom JavaScript code can be executed on the client as needed. The table below defines a set of static methods on the CallbackResult class which can be used to interact with browser content.  


CallbackResult
Static Method
Description
CreateSetContent Set the outerHTML property of an html element. 
CreateSetInnerContent Set the innerHTML property of an html element.
CreateSetImageSource Set the src property of an image element. 
CreateJavaScript Execute JavaScript on the client.
CreateIncludeJavaScript Include JavaScript on the client
CreateIncludeStyleSheet Include a CSS style sheet on the client

The following example illustrates how to execute a line of JavaScript code associated with a custom CallbackResult using the CreateJavaScript static method.  A Map control named "Map1" will generate the callback results for a Web response, so the custom CallbackResult will be added to Map1's callback results collection. When this code is executed at runtime and processed by Web ADF JavaScript a message box will display in the browser containing the phrase "Hello World":

[C#]
string javascriptString = "alert('Hello');";
CallbackResult customCallbackResult = CallbackResult.CreateJavaScript(javascriptString);
Map1.CallbackResults.Add(customCallbackResult);

Each custom CallbackResult instance is designed to be processed by the Web ADF JavaScript function processCallbackResult() in the ESRI.ADF.System.js library. The processCallbackResult() contains the following logic to process the custom CallbackResult content:

[JavaScript]
if(action==='javascript') {
	var method = function() {
		try { eval(params[0]); }
. . .}
else if (action==="content") {
	var o = $get(controlID);
	if (o) { o.outerHTML=params[0]; }
. . .}
else if (action==="innercontent") {
	var o2 = $get(controlID);
	if (o2) { o2.innerHTML=params[0]; validResponse = true; }
. . .}
else if (action==="image")
{
	var o3 = $get(controlID);
	if (o3) { o3.src = params[0]; }
. . .}
else if (action=='include') {
	var id = params[0];
	var elm = (id?$get(id):null);
. . .
	if(elm) { elm.parentNode.removeChild(elm); }
	document.getElementsByTagName('head').item(0).appendChild(elm);
. . .}
				
Many samples included with the developer help illustrate the use of custom callback results and the CallbackResult class including Common_Callback, and Common_SelectBufferTool


Internal callback result management in Web ADF controls

In some cases, a Web ADF control may generate callback results without requiring an explicit call to refresh the control on the server. This is often the case with the Map control. Merely changing map extent or scale will automatically cause the Map control to update its callback result collection. In other cases, an explicit call to refresh is required, such as when layer visibility changes or a resource is added or removed. It's important to be aware that an explicit call to refresh the Map control is not always necessary. In many cases, you do not need to explicitly copy callback results from one Web ADF control to another. Listed below are a number of inherent relationships between Web ADF controls:


Exceptions for non-Web ADF controls

In general, some controls that have been added to the page, but are not visible or do not contain any content, do not add an html element when the page is rendered in the client browser. Since callbacks are designed to work with the browser’s DOM to update content dynamically, they need an element (object) to work with.  The GridView control exhibits this behavior.  If the GridView has been added to a page, but is not visible or is empty, no complimentary object on the client is available.  When the GridView is populated on the server and needs to be rendered on the client via a callback, you need to provide a location to render the content using the browser's DOM.  One widely accepted solution to this problem involves using a div element on the client to wrap the GridView. When the GridView needs to be updated via a callback, the innerHTML of the div can be completely replaced and the location and style of the GridView is maintained in the page, regardless of its visibility.  Two samples illustrate this solution: Common_AddCustomTool and Common_SelectBufferTool