Here is screen shot of my implementation:

You are probably familiar with the differences between the RadAjaxManager and RadAjaxManagerProxy. You are only allowed one RadAjaxManager instance on a page. That is - if you have a RadAjaxManger in a user control and then in a content page using that user control - you will have to use a proxy. No problem here - you can easily put your RadAjaxManager in your MasterPage f.ex., and then use the proxy implementation on other pages in your system. This works without a glitch - until you start making Ajax requests using the OnAjaxRequest feature.
When solving this issue, I spent quite a bit of time searching the web for a solution. Todd Anglin's blog from February 25, 2010 put me on the right track, but there were still pieces missing...
When using the RadAjaxManagerProxy, you should be aware of the fact that this control copies the exact same RadAjaxManager designer configuration. It does exacly what the name indicates - acts as a proxy for the main RadAjaxManager control. The proxy control does, therefore, not provide any client side functionality as the manager does. There is no client-side object, no OnAjaxRequest function, and no client-side events. This is where the problem lies...
How can I make an Ajax call when there is no OnAjaxRequest function in the proxy? Well, I thought maybe I could put the OnAjaxRequest in the "parent" RadAjaxManager which resides on the master page, but that won't work either since I have other ajax request I want to make from other parts of the system - like other content pages or other user controls.
Well, thankfully, there is a solution. To use the events from the "parent" RadAjaxManger, you must get a reference to it from the page where the proxy resides. This is done through code - here are some examples from my implementation:
First we set up the "parent" RadAjaxManager in the master page.
From my master page:
<telerik:RadAjaxManager ID="RadAjaxManager1" runat="server" EnablePageHeadUpdate="False" EnableAJAX="true" />
Then we set up the RadAjaxManagerProxy in the user control or the content page (or as many places as you want). First we must include a RadScriptManager. You may not need the globalization stuff that goes on in my script manger. Then we define the RadAjaxManager and last the RadAjaxLoadingPanel.
From my user control "myUserControl.ascx":
<telerik:RadScriptManager ID="RadScriptManager" Runat="server" EnableScriptLocalization="true" EnableScriptGlobalization="true">
<Scripts>
<asp:ScriptReference NotifyScriptLoaded="true" Path="~/App_Themes/Res/Script.js" />
<asp:ScriptReference Path="~/Scripts/StringResources.js" ResourceUICultures="nb-NO, sv-SE, da-DK, fi-FI, de-DE, fr-FR, nl-NL, en-US, ru-RU" />
</Scripts>
</telerik:RadScriptManager>
<telerik:RadAjaxManagerProxy ID="RadAjaxManagerMenuEdit" runat="server">
<AjaxSettings>
<telerik:AjaxSetting AjaxControlID="rtsMenuTab">
<UpdatedControls>
<telerik:AjaxUpdatedControl ControlID="rtsMenuTab" LoadingPanelID="RadAjaxLoadingPanel1" />
</UpdatedControls>
</telerik:AjaxSetting>
</AjaxSettings>
</telerik:RadAjaxManagerProxy>
<telerik:RadAjaxLoadingPanel ID="RadAjaxLoadingPanel1" runat="server" />
As you can see from this code, I set the updated control and loading panel exactly as I would do for a "real" RadAjaxManager. However, it is not possible to set the OnAjaxRequest in the proxy manager. This will, therefore, be done in my user control code behind as follows:
From my user control code behind "myUserControl.ascx.cs":
protected void Page_Load(object sender, EventArgs e)
{
//Get reference to AjaxManager (from Master)
var manager = RadAjaxManager.GetCurrent(Page);
manager.ClientEvents.OnRequestStart = "RequestStart";
manager.ClientEvents.OnResponseEnd = "ResponseEnd";
//Create a new delegate to handle the AjaxRequest event
manager.AjaxRequest += new RadAjaxControl.AjaxRequestDelegate(RadAjaxManagerMenuEdit_AjaxRequest);
//Add your ajax settings programmatically (with ref to Master manager)
//manager.AjaxSettings.AddAjaxSetting(manager, this.RadPageViewPreview);
}
I now have a reference to the "parent" RadAjaxManager (first line of code), I add a couple of client events that I want to execute in the user control, and finally create a new delegate to handle the Ajax request event. You may also add your ajax settings programatically, as the last line of code shows. However, I did not implement this in my code, as I did all my ajax settings inline in "myUserControl.ascx".
In the same user control, I have created the routine that handles my ajax request as follows:
From my user control code behind "myUserControl.ascx.cs":
protected void RadAjaxManagerMenuEdit_AjaxRequest(object sender, Telerik.Web.UI.AjaxRequestEventArgs e)
{
string strArg = e.Argument;
string caller = (strArg.Split('*'))[0]; //First argument is always name of caller, i.e., "MenuTab*67*EDIT"
if (caller == "MenuTab")
{
//Will get in strArg the following "MenuTab*[menu_id]*[name of context function]. F.ex. "MenuTab*67*EDIT".
string menuId = (strArg.Split('*'))[1];
string contextMenuCommand = (strArg.Split('*'))[2];
string menuUrl = "~/MenuManager.aspx?menuid=";
Response.Redirect(menuUrl + menuId + "&cmd=" + contextMenuCommand);
}
}
There are a few important things that goes on in this code. However, before I explain that, I will show you the JavaScript that I wrote to handle the client events in "myUserControl.ascx". Here is the JavaScript code:
From my user control "myUserControl.ascx":
<telerik:RadCodeBlock ID="RadCodeBlock1" runat="server">
<script type="text/javascript">
<!--
var isAjaxActive;
var tabValue;
function onContextMenuItemSelected(sender, e)
{
if (!isAjaxActive)
{
//Get context menu item ("NEW", "EDIT" or whatever the Value parameter is.).
var contextMenuItem = e.get_item().get_value();
var ajaxManager = $find("<%= RadAjaxManager.GetCurrent(Page).ClientID %>");
//Must always follow this standard when making ajax calls - "[name of caller]*..."
ajaxManager.ajaxRequest("MenuTab" + "*" + tabValue + "*" + contextMenuItem);
}
}
function showContextMenu(sender, e)
{
//Get the menu_id of the clicked tab which is stored in the value field.
tabValue = e.get_tab().get_value();
var menu = $find("<%= rcmMenuTab.ClientID %>");
if (menu != null)
{
var rawEvent = e.get_domEvent().rawEvent;
menu.show(rawEvent);
$telerik.cancelRawEvent(rawEvent);
}
}
function RequestStart(sender, args)
{
if (isAjaxActive)
{
args.set_cancel(true);
}
else
{
isAjaxActive = true;
}
}
function ResponseEnd(sender, args)
{
isAjaxActive = false;
}
-->
</script>
</telerik:RadCodeBlock>
And here is the inline definitions for my RadTabStrip and RadContextMenu.
From my user control "myUserControl.ascx":
<div id="menuTab">
<telerik:RadTabStrip runat="server" ID="rtsMenuTab" CausesValidation="false" EnableEmbeddedSkins="false" Skin="LuminoTabStrip"
SelectedIndex="0" DataSourceID="odsMenu" DataFieldID="menu_prioritet" DataFieldParentID="parent_id" DataValueField="menu_id"
EnableViewState="false" EnableSubLevelStyles="false" Orientation="HorizontalTop" OnDataBound="rtsMenuTab_DataBound"
DataTextField="menu_tekst" OnTabDataBound="rtsMenuTab_TabDataBound" OnClientContextMenu="showContextMenu">
</telerik:RadTabStrip>
<telerik:RadContextMenu ID="rcmMenuTab" runat="server" EnableRoundedCorners="true" EnableShadows="true" OnClientItemClicked="onContextMenuItemSelected">
<Items>
<telerik:RadMenuItem Text="<%$ Resources: Resource, lnkNyMeny %>" Value="NEW" ImageUrl="~/images/page_add.png" />
<telerik:RadMenuItem Text="<%$ Resources: Resource, btnEditMenu %>" Value="EDIT" ImageUrl="~/images/page_edit.png" />
</Items>
</telerik:RadContextMenu>
</div>
As you can see from this code, I make a call to the JavaScript "showContextMenu" when the user right-clicks in the RadTabStrip (defined as OnClientContextMenu="showContextMenu" in the RadTabStrip). The JavaScript "showContextMenu", first gets the menu_id of the clicked tab (this is stored in the "DataValueField"), then it displays the context menu and cancels the default context menu action from the operating system.
Then, when you click on one of the context menus - either "New" or "Edit" in my case - the JavaScript "onContextMenuItemSelected" is called. I now get the value parameter from the context menu, then I get a handler to the "parent" RadAjaxManager". I am then ready to make the Ajax request as shown in the last line of code below.
//Get context menu item ("NEW", "EDIT" or whatever the Value parameter is).
var contextMenuItem = e.get_item().get_value();
var ajaxManager = $find("<%= RadAjaxManager.GetCurrent(Page).ClientID %>");
//Must always follow this standard when making ajax calls - "[name of caller]*..."
ajaxManager.ajaxRequest("MenuTab" + "*" + tabValue + "*" + contextMenuItem);
There is a trick here, and that is to include the "name of the caller" in all Ajax request. Since we use a proxy manager, all Ajax calls will expose everything from the "parent" Ajax manager. This will only be a problem if you have several different "OnAjaxRequest" on the same page. In my case, I have an Ajax request in a content page that uses this user control ("myUserControl.ascx"). The RadAjaxManager is defined in the master page, and the content page in question therefore has a RadAjaxManagerProxy definition as does the user control. Thus, the page that is executed will then have a RadAjaxManager from the master page and one proxy from the content page and one proxy from the user control.
In a scenario like this, RadAjaxManager will call both "OnAjaxRequest" functions. In my case, the "RadAjaxmanagerMenuEdit_AjaxRequest" in "myUserControl.ascx.cs" will be called, and a routine called "RadAjaxManagerArticle_AjaxRequest" in the content page (containg the myUserControl.ascx) will also be called. We, of course, need a way to distinguish between the two calls, and I have done this through the arguments I set in the JavaScript code. Note the comment in the code above "//Must always follow this standard when making ajax calls - "[name of caller]*...". I therefore always put the name of the caller - in the case above it is "MenuTab" - as the first parameter in the argument that I pass to "RadAjaxManagerMenuEdit_AjaxRequest" or "RadAjaxManagerArticle_AjaxRequest" (in the case of this latter, the name of the caller will be "Article*..."). I then use the "Split" function to get the various arguments I wish to pass into the ajax routine - see code below:
From my user control code behind "myUserControl.ascx.cs":
protected void RadAjaxManagerMenuEdit_AjaxRequest(object sender, Telerik.Web.UI.AjaxRequestEventArgs e)
{
string strArg = e.Argument;
string caller = (strArg.Split('*'))[0]; //First argument is always name of caller, i.e., "MenuTab*67*EDIT"
if (caller == "MenuTab")
{
//Will get in strArg the following "MenuTab*[menu_id]*[name of context function]. F.ex. "MenuTab*67*EDIT".
string menuId = (strArg.Split('*'))[1];
string contextMenuCommand = (strArg.Split('*'))[2];
string menuUrl = "~/MenuManager.aspx?menuid=";
Response.Redirect(menuUrl + menuId + "&cmd=" + contextMenuCommand);
}
}
The code here is now only executed when the caller is "MenuTab", thus avoiding that the code also executes when making Ajax calls from "Article" - and we achieve what was the intention.
Good luck - Ajax is great, but sometimes a few tricks can make life a bit easier :)
André Vold