What if there was a "magical" panel control that, when you drag-n-drop ordinary, old-fashioned, ASP.NET controls, "magically" transforms them to AJAX-enabled controls? Impossible! Well, this article claims that such a panel can exist (
AjaxPanel) and sadly, there's no magic about it; it's all plain C# code.
Update - 12 Nov 2005: The MagicAjax framework is now hosted on SourceForge. Many improvements and features have been added since the initial release, including support for ASP.NET 2.0.
Using the code
I have included a demo project to show you how to convert the existing plain postback controls to AJAX-like ones.
This page tries to be a chat application. I will not get into the details of how it works; it was created just for demonstration purposes. It uses the standard ASP.NET controls, no mystery here. The buttons cause a postback to the server and the page reloads and fills the controls with the new data.
This page uses the same controls but it works quite differently. The controls are refreshed instantly and without any reloading by the browser. That's right, AJAX is here.
Hey, how did you do that
There are four steps required to convert BubisChat.aspx to AjaxBubisChat.aspx (or to apply AJAX to any page using this framework):
Make the page inherit from AjaxPage (optional)
public class AjaxBubisChat : Ajax.AjaxPage
AjaxPage is not required; it just handles the callback event and provides some useful properties for convenience. To handle the callback event in a page that inherits from
AjaxPage, you override the
protected override void OnCallBack(EventArgs e)
txtMsg.Text = chatData.msgText.ToString();
If the page doesn't inherit from
AjaxPage, it can handle the callback event by implementing the
public interface ICallBackEventHandler
The callback is like a postback but without the reloading of the page by the browser. I'll explain what the callback does a little later. For reasons that will become clear later, the Load event of the page and its controls are not raised during a callback. You must use the callback event instead.
During a callback, the
HttpContext of the page is invalid, so you can't use the
Response properties of
System.Web.UI.Page, you have to use the
CallBackHelper.Response properties instead. The
AjaxPage provides valid
Response properties so that you don't have to replace them in your code for the ones from
Put inside an AjaxPanel the controls that will get refreshed without a postback
It can be one
AjaxPanel for each
ListBox, or one
AjaxPanel for all of them. The buttons should be inside an
AjaxPanel, so that their submit function is replaced automatically for a callback function. In this example, I just put all the controls inside one
AjaxPanel for convenience.
Configure the web.config file
<add name="AjaxHttpModule" type="Ajax.AjaxHttpModule, Ajax" />
<system.web> section, and:
<add key="CallBackScriptPath" value="/ajax/script" />
<appSettings> section of the web.config file.
AjaxHttpModule processes the callback at the
AcquireRequestState event of the
HttpApplication, after the request has been authenticated. The default script path is valid if you extract the source files to the wwwroot path. If you extract them to another directory, you should change the
CallBackScriptPath of the application settings accordingly.
Enable the CallBackTimer on the page (optional)
This is required so that the chat textbox is automatically refreshed if there are new messages to display. Most pages don't need automatic refresh, so just ignore this if that's the case.
AjaxPanel either by code or by using the Visual Studio Designer.
So, what does a callback do
The job of the callback is to invoke server-side control events (and a special
Now, it is getting more interesting... A page that is AJAX-enabled is stored as a session state variable. When a callback is invoked, the
AjaxHttpModule intercepts it, finds the originating page from the session and invokes the appropriate events for the controls of the page without reloading the original page.
Why store the page in the session
- There is no overhead because of constant reloading of the page and its controls.
- The illusion of AJAX is that the page behaves like a desktop application. In a desktop application the controls are kept in memory without reloading them every time a button is pressed, and the controls can be added or removed dynamically. Well, by persisting the page in the session we don't have to reload the controls and the controls can be added or removed dynamically; and if you add them to the
AjaxPanel they will actually appear on the browser too!
In order for a page to be stored in the session, it must contain at least one
AjaxControl control (base class of
AjaxPanel). The session key that is used is the URL of the originating page so that different pages can be distinguished from one another.
The callback doesn't have to come from a control contained inside an
AjaxPanel, it can be invoked from any control on the page, as long as it is properly configured to call the appropriate callback function, like this:
Button btnSend = new Button();
" return false;");
CallBackHelper.GetCallbackEventReference method provides the
AJAXCbo.DoPostCallBack call on the client side, and
return false; is added so that the
OnClick event can override the submit function.
AjaxPanel, by default, automatically configures all the submit buttons that it contains to call the callback function and replaces the
__doPostBack calls of normal postback with a
AJAXCbo.DoPostCallBack call. If you want to manually set the
OnClick event of your controls, set the
SetCallBackForChildPostBack properties of
The mysterious AjaxPanel
The task of
In addition, if the
AjaxPanel encounters any
RenderedByScriptControl controls (
AjaxPanel inherits from this class), it ignores them and lets them take care of their "reflection" to the browser. Thus, if an
AjaxPanel (parent) contains another
AjaxPanel (child), and a control of the child-
AjaxPanel is altered, the parent-
AjaxPanel won't send the entire HTML rendering of the child-
AjaxPanel, but instead the child-
The known limitations are:
To sum up
I'm not going to get into the details of the inner workings of the classes. I have tried to document every method, so anyone wanting to extend the AJAX controls that are provided, I strongly recommend reading the comments of all the methods and the classes. For the rest who just want to use the framework:
- The script path of the demo page is valid only if you extract the source files to the wwwroot path. If you extract them to another directory you should change the
CallBackScriptPath of the application settings of web.config accordingly.
- Follow the four steps that I have mentioned in the Using the code section of this article.
- Read the comments of AjaxPage.cs, CallBackHelper.cs and ICallBackEventHandler.cs.
- Read the comments of the
public properties of
- Read the comments of the
- You must use the
CallBackHelper.Response properties in the code of your page, unless it inherits from
AjaxPage. The same applies to your user controls and the
AjaxUserControl that are provided.
- Do not use
Panel controls inside an
AjaxPanel because even if only one child of the
Panel changes, all its children will have to be rendered on the client. Use
AjaxPanel controls instead.
- After the update of 23-9-2005, the framework can handle the
Server.Transfer methods during a callback. You don't have to change them in your code.
CallBackHelper.End instead of
Response.End during a callback.
- Always keep in mind that the callback is different from postback, because the page and its controls are persisted in the session, thus the
Load event is not raised, and you can add/remove controls from the
AjaxPanel dynamically, and the changes will be reflected on the browser. A bit like manipulating the controls of a desktop application.
Points of interest
AjaxPanel handles the "Browser Back Button" problem as well. The "Browser Back Button" problem is that by pressing the Back button, the browser loads the HTML page by its cache, so any AJAX changes made to the page are lost, while the user still expects to see the same page that he was viewing before.
CallBackStartup) on the server. When the
CallBackStartup event is raised,
AjaxPanel renders all of its children on the client page, thus restoring the previous page that the user was viewing.
I hope you find this framework useful. I encourage you to experiment with it, and if some fancy, jaws-dropping, eyes-bleeding, amazing control comes out of it, please share it with us.
- 16-9-2005 - Initial release.
- 16-9-2005 - Added in the article the browser detection limitation, noted by Cristian O.
- Inheriting from
AjaxPage is no longer necessary to use the AJAX Framework. Moved its functionality to other classes except the handling of the callback event and the
- Added AjaxUserControl.cs with similar functionality as
- Replaced the
AjaxHttpHandler with the
- Added IPostDataLoadedEventHandler.cs.
- Added NoVerifyRenderingPage.cs.
- Added a few helper functions and properties to CallBackHelper.cs.
- Other minor additions and improvements.
- Updated the text of the article.
- Fixed a bug in
AjaxPanel, noted by Cristian O.
- Fixed CallBackObject.js to make checkboxes work properly (noted by collab man).
- Added the
CallBackHelper.Redirect method and included it in the Sum up section of the article (noted by mdissel).
AjaxHttpModule can now handle
Server.Transfer during a callback.
CallBackHelper.Redirect is not required. Updated the article in the Sum up section.
- Fixed a bug noted by collab man (controls not getting refreshed when callback is invoked by
- Fixed a bug noted by JunkyMail1 (multi-select
ListBox not working properly).
- Enhancements to CallBackObject.js provided by Cristian O. ("Loading..." indicator, callback timeout, response returned during an error is displayed on page).
AjaxPanel works properly now when its
Visible property is changed.
- Fixed the hidden controls persisting their state bug noted by mdissel.
- Fixed the
RadioButtonList problem noted by CarinLindberg.
- In CallBackObject.js, fixed the post data not getting sent correctly when they contain '+', noted by Ricardo Stuven.
- Added the fix for handling
CheckBoxList, provided by Ricardo Stuven.
- Included in the article the SourceForge and homepage link for MagicAjax.