I've been a bit slow on the Ajax and Visual Studio 2005 uptake. So what I'm saying now may seem bloody obvious to a some!
One thing that irritated me initially is that studio 2005 has running documents moved to something called Script Editor. Its not enabled by default so you need to do the following in the Visual Studio 2005 IDE
* Tools > Customize.
* Select the Command Tab
* Select Debug from the list, on the right hand side drag Script Editor somewhere.
This will enable you to have running documents which allow you to debug client side script. Start up the application in debug mode. Navigate to the page you wish to debug and then have a look in Script Editor. You will see all active documents that are on the client. Insert a breakpoint as you would with normal server side code and wala. Unfortunitly you can only do this at runtime and it does not remember your breakpoints.
You also need to ensure that you have enabled browser debugging in IE (you have to go through IE even if your using other browsers)
In IE go to Tools > Internet Options... > Advanced > Uncheck Disable Script Debugging (Internet Explorer) or if your using another browser (other). Let me know if this works for you.
I decided to compare both Microsoft vision for Ajax (not Atlas just the ICallbackEventHandler) and "raw" Ajax.NET. I missioned around for a while with MS rather weird implementation but managed to create what I consider to be a very simple implementation of ICallbackEventHandler. The problem really is that all calls that you create will return to the same methods. This means with multiple calls you will have to handle them inside the same methods. The "multiple" offenders are RaiseCallbackEvent(string eventArgs) and GetCallbackResult(). Please for the love of Mass don't go down the route of semi implementing ICallbackEventHandler and Ajax.NET. It just makes things too complex! Its not a best of breads its a mongrel!!!
If you do need to have multiple calls and you want to use use ICallbackEventHandler the following control that I cleverly sweated out should do it for you.
The other option would be to implement it directly from your page public partial class _Default : System.Web.UI.Page, ICallbackEventHandler. I do predict that your code will be very messy if you choose the latter option!
The C#
using System.Web.UI;
using System;
public delegate string AjaxGetCallbackResult();
public delegate void AjaxRaiseCallbackEvent(string eventArgument);
public class AjaxEventControl : Control, ICallbackEventHandler
{
public event AjaxGetCallbackResult AjaxGetCallbackResultEvent;
public event AjaxRaiseCallbackEvent AjaxRaiseCallbackEventEvent;
public void RaiseCallbackEvent(string eventArgument)
{
if (AjaxRaiseCallbackEventEvent != null)
{
AjaxRaiseCallbackEventEvent(eventArgument);
}else
{
throw new Exception("For the love of MASS!!!!! You have not implemented the AjaxRaiseCallbackEventEvent.");
}
}
public string GetCallbackResult()
{
if (AjaxGetCallbackResultEvent != null)
return AjaxGetCallbackResultEvent();
throw new Exception("For the love of MASS!!!!! You have not implemented the AjaxGetCallbackResultEvent.");
}
}
Declare an instance of AjaxEventControl inside your webpage.
public AjaxEventControl userAjaxEventControl = new AjaxEventControl();
private string userReturnFromServer = "";
You will need to setup the mapping inside the onInit event as such
protected override void OnInit(EventArgs e)
{
userAjaxEventControl.AjaxGetCallbackResultEvent += new AjaxGetCallbackResult(userAjaxEventControl_AjaxGetCallbackResultEvent);
userAjaxEventControl.AjaxRaiseCallbackEventEvent += new AjaxRaiseCallbackEvent(userAjaxEventControl_AjaxRaiseCallbackEventEvent);
//AddParsedSubObject will add the control to the page hierarchy.
this.AddParsedSubObject(this.userAjaxEventControl);
string callbackSource= Page.ClientScript.GetCallbackEventReference(userAjaxEventControl, "argument", "UserCallback", "context", "ErrorCallback", true);
string functionSource = @"function RetrieveDataRows(argument, context)
{ " + callbackSource + "; }";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RetrieveDataRows", functionSource, true); base.OnInit(e);
}
void userAjaxEventControl_AjaxRaiseCallbackEventEvent(string eventArgument)
{
DataTable dataTable = AjaxRD.DataAccess.Users.Get(Convert.ToInt32(eventArgument));
HtmlTableFormatter htmlTableFormatter = new HtmlTableFormatter();
userReturnFromServer = htmlTableFormatter.GetHtml(dataTable);
}
string userAjaxEventControl_AjaxGetCallbackResultEvent()
{
return userReturnFromServer ;
}
The JavaScript is pretty simple.
<
script language="javascript" type="text/jscript">
function RetrieveInformation()
{
var numberOfRows = document.forms[0].numberOfRowsTextBox.value;
RetrieveDataRows(numberOfRows, "RetrieveInformation");
}
function UserCallback( result, context )
{
var userTableDivObject = document.getElementById('userTableDiv');
userTableDivObject.innerHTML += result;
}
function ErrorCallback( error, context )
{
var userTableDivObject = document.getElementById('userTableDiv');
userTableDivObject.innerHTML += 'Something went wrong ' + error;
}
</
script>
<form id="Form1" runat="server">Number of Rows<br />
<input id="txtNumber" name="numberOfRowsTextBox" type="text"/>
<button id="retrieveInformationButton" onclick="RetrieveInformation()">Retrieve Info</button>
<div id="userTableDiv">
</div>
</form>
The benefit of doing this is you can declare multiple instances of AjaxEventControl and the events can be more easily controlled. I hope this is clear!! If its not please say so and I will provide the full source and more detailed explanation.
Now this is what cracks me up! The Ajax.Net implementation is really so much more simple! The JavaScript and HTML
<
script language="javascript" type="text/javascript">
function
RetrieveInformation(divName)
{
var userInformation = AjaxDotNet.GetUserInformation( document.forms[0].numberOfRowsTextBox.value ).value;
var userTableDivObject = document.getElementById(divName);
userTableDivObject.innerHTML += userInformation;
}
</
script>
<form id="form1" runat="server">Number of Rows<br />
<input id="txtNumber" name="numberOfRowsTextBox" type="text" />
<button id="retrieveInformationButtonDiv1" onclick="RetrieveInformation('userTableDiv')" type="button">Retrieve Info Div 1</button>
<button id="retrieveInformationButtonDiv2" onclick="RetrieveInformation('userTableDiv2')" type="button">Retrieve Info Div 2</button><table>
<tr>
<td><div id="userTableDiv">
</div>
</td><td><div id="userTableDiv2">
</div>
</td>
</tr>
</table>
</form>
The C#
protected void Page_Load(object sender, EventArgs e)
{
AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxDotNet));
}
[AjaxPro.
AjaxMethod]
public string GetUserInformation(int numberOfUsers)
{
DataTable dataTable = AjaxRD.DataAccess.Users.Get(numberOfUsers);
HtmlTableFormatter htmlTableFormatter = new HtmlTableFormatter();
return htmlTableFormatter.GetHtml(dataTable);
}
I can't see the point of using ICallbackEventHandler! The next problem I have is managing the data. Does anyone have any ideas as to the rendering of the string based data any paradigms or frameworks.