ASP.NET AJAX 1.0 Released

It was over a year ago that I started working with a product called Microsoft Atlas.  I wanted to use it to build a rich web client for managing licensed commercial music for a cable television studio, based on the expectation that the client must work on multiple platforms (hence a web application) and at the same time provide rich functionality such as our sponsors were used to in their desktop applications (hence Ajax).  The whole time I was building it, I had the expectation that the final release was right around the corner.  In December of 2005, Atlas was rumored to have a release date sometime in the March or April range.  A year, a name change, and a few scope changes later, it has finally arrived.

The product is an example of Microsoft coming late to the party.  Based on a key bit of technology originally developed by Microsoft engineers over seven years ago, the XMLHttpRequest API, alternate vendors like Yahoo, Google and others helped to develop a style of programming called Ajax that allowed web clients to talk to a webserver without a page refresh.  Ajax in turn was adopted by advocates of the term Web 2.0 as one of the hallmarks of the phenomena they wished to tout in an attempt to revitalize interest in the web as a business platform following the disaster that we now all know as The IT Bubble of the 90’s.

Why Microsoft took so long to get around to it is an open question.  Very likely, they were busy getting on the web services band wagon as a way to promote Smart Clients as their technology of choice for integrating the desktop with the web.  While very cool in its own right, it hasn’t really achieved the same mindshare that Ajax has among web developers, and so — better late than never — we now have ASP.NET Ajax to kick around, and it can be downloaded here.

In the meantime, special recognition should be given, I think, to Brent Ashley, who in 2000 came out with something he called JavaScript Remote Scripting, which used javascript to generate dynamic iFrames in order to provide the same functionality that the XMLHttpRequest API does.  In an alternate universe, JSRS could have been the inspiration for Web 2.0.  Brent Ashley still supports his scripts here, a placeholder for his mark on the history of technology.

Converting to ASP.NET Ajax Beta 2 (A Guide for the Perplexed)


There are a few good guides already on the internet that provide an overview of what is required to convert your Atlas CTP projects to Ajax Extensions.  This guide will probably not add anything new, but will hopefully consolidate some of the advice already provided, as well as offer a few pointers alluded to by others but not explained.  In other words, this is the guide I wish I had before I began my own conversion project.


1. The first step is to download install the Ajax Extensions beta 2 and the Ajax Futures (value added-) November CTP.  One problem I have heard of occurred when an associate somehow failed to remove his beta 1 dlls, and had various mysterious errors due to using the wrong version. 


2. Create a new Ajax Extensions project. This should provide you with the correct library references and the correct web configuration file.  Here are the minimum configuration settings needed for an ASP.Net Ajax website to work:



</configuration>


     <system.web>
     <pages>
     <controls>
            <add tagPrefix=”asp” namespace=”Microsoft.Web.UI” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
           <add tagPrefix=”asp” namespace=”Microsoft.Web.UI.Controls” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
           <add tagPrefix=”asp” namespace=”Microsoft.Web.Preview.UI” assembly=”Microsoft.Web.Preview”/>
     </controls>


     <compilation debug=”true”>
          <assemblies>
                <add assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
          </assemblies>
     </compilation>

</configuration>

 


You also need to make sure that you have a reference to the Microsoft.Web.Extensions dll as well as to the Microsoft.Web.Preview dll, if you intend to use features such as drag and drop or glitz. Both of these dlls should be registered in the GAC, although it wasn’t for me.  To make sure it was available in the GAC, I had to add a new registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\ASP.NET AJAX 1.0.61025  with a default value indicating the location of the ASP.Net Ajax dlls: c:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025″


On a side note, there seems to currently be some ambiguity over whether the Microsoft.Web.Extensions dll can or cannot simply be placed in your bin folder rather than placed in the GAC.  It seems to work, even though the official documentation says it should not.


 


3. Wherever you used to use the shortcut “$” as a shorthand for “document.getElementsById“, you will now need to use “$get” .  I usually need to go through my Atlas code three or four times before I catch every intance of this and make the appropriate replacement.


 


4. Sys.Application.findControl(“myControl”) is now simplified to $find(“myControl”).


 


5. Wherever you used to use this.control.element, you now will use this.get_element().


 


6. The “atlas:” namespace has been replaced with the “asp:” namespace, so go through your code and make the appropriate replacements.  For example,



<atlas:ScriptManager ID=”ScriptManager1″ runat=”server”/>


is now



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”/>


 


7. Script References have changed.  The ScriptName attribute is now just the Name attribute.  The files that used to make up the optional ajax scripts are now broken out differently, and so if you need to use the dragdrop script file or the glitz script file, you now will also need to include PreviewScript javascript file.  This:



 


<atlas:ScriptManager ID=”ScriptManager1″ runat=”server”>
     <Scripts>
          <atlas:ScriptReference ScriptName=”AtlasUIDragDrop” />
          <atlas:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
     </Scripts>
</atlas:ScriptManager>


is now this:



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
     <Scripts>
          <asp:ScriptReference Assembly=”Microsoft.Web.Preview” Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js” />
          <asp:ScriptReference Assembly=”Microsoft.Web.Preview” Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js” />
          <asp:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
     </Scripts>
</asp:ScriptManager>


 


8. Namespaces have changed, and you may need to hunt around to find your classes.  For instance, Sys.UI.IDragSource is now Sys.Preview.UI.IDragSource, and for the most part you can probably get away with replacing all your Sys.UI namespaces with Sys.Preview.UI.  On the other hand, Sys.UI.Behavior has stayed where it is, so this is not always going to be the case.  The method setLoctation has also shifted namespaces.  It used to be found in Sys.UI.  It is now in Sys.UI.DomElement.


 


9. Xml Scripting change: Xml scripting, which allows you to use javascript in a declarative manner, is now part of the Value Added CTP.  As I understand it, the Value Added CTP, also known as Ajax Futures, includes lots of stuff originally included in the Atlas CTP but deemed to be of lower priority than the core Ajax Extensions features.  In order to meet a tough deadline, these have been set aside for now.  The Ajax Toolkit, in turn, is heavily dependent on these value added features, since the toolkit components tend to leverage the common javascript libraries such as Glitz much more than the specifically Ajax features provided with the core release.  The syntax for adding custom behaviors using Xml Scripting has changed, while the syntax for built in behaviors is the same.  An Xml Scripting region used to look like this:



 


<script type=”text/xml-script”>
   <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″>
      <components>
         <control id=”dropZone”>
           <behaviors>
               <DropZoneBehavior/>
           </behaviors>
         </control>
         <control id=”draggableDiv”>
           <behaviors>
             <floatingBehavior handle=”handleBar” />
           </behaviors>
         </control>
      </components>
  


Now it looks like this:


<script type=”text/xml-script”>
   <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″
xmlns:fooNamespace=”Custom.UI”>
      <components>
        <control id=”dropZone”>
          <behaviors>
            <fooNamespace:DropZoneBehavior/>
          </behaviors>
        </control>
      <control id=”draggableDiv”>
         <behaviors>
              <floatingBehavior handle=”handleBar” />
         </behaviors>
      </control>
    </components>
  </page>
</script>


Note: The AspNet AJAX CTP to Beta Whitepaper has a slightly different syntax, but this appears to be a typo, and the one I have provided above is the correct grammar.


10.  Adding behaviors using javascript has changed.  The biggest thing is that you no longer explicitly have to convert a DOM object to an ASP.Net Ajax object, as this is now done beneath the covers.  The get_behaviors().add(…) method has also been retired.  For my particular conversion, this code:



function addFloatingBehavior(ctrl, ctrlHandle){
     var floatingBehavior = new Sys.UI.FloatingBehavior();
     floatingBehavior.set_handle(ctrlHandle);
     var dragItem = new Sys.UI.Control(ctrl);
     dragItem.get_behaviors().add(floatingBehavior);
     floatingBehavior.initialize();
     }



got shortened to this:



function addFloatingBehavior(ctrl, ctrlHandle){
     var floatingBehavior = new Sys.Preview.UI.FloatingBehavior(ctrl);
     floatingBehavior.set_handle(ctrlHandle);
     floatingBehavior.initialize();
     }


This can in turn be shortened even further with the $create super function: 



function addFloatingBehavior(ctrl, ctrlHandle){


   $create(Sys.Preview.UI.FloatingBehavior, {‘handle’: ctrlHandle}, null, null, ctrl);


}


 


11.  Closures and Prototypes:


You ought to convert javascript classes written as closures to classes written as prototypes.  Basically, instead of having private members, properties and methods all in the same place (called, it turns out, “closures”), they are now separated out into an initial definition that includes the members, and then a definition of the prototype that includes the various methods and properties, which are in turn rewritten using a slightly different grammar.  Here is a reasonably good overview of what the prototype object is used for.  Bertand LeRoy‘s two posts on closures and prototypes is also a good resource.


12. You basically follow the following steps to mechanically rewrite a closure as a prototype. First, change all your private variable declarations into public member declarations.  For instance, the following declaration:



var i = 0;


should now be:



this.i = 0;


 


Consolidate all of your members at the top and then place a close bracket after them to close your class definition.


13.  Start the first line of code to define your prototype.  For instance, in my dropzonebehavior class, I replaced this:



 Custom.UI.DropZoneBehavior = function() {
     Custom.UI.DropZoneBehavior.initializeBase(this);
     initialize: function(){
          Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘initialize’);
          // Register ourselves as a drop target.
          Sys.Preview.UI.DragDropManager.registerDropTarget(this);
          }


}


with this:



Custom.UI.DropZoneBehavior = function() {
       Custom.UI.DropZoneBehavior.initializeBase(this);
}



Custom.UI.DropZoneBehavior.prototype = {
     initialize: function(){
             Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘initialize’);
            // Register ourselves as a drop target.
            Sys.Preview.UI.DragDropManager.registerDropTarget(this); 
            }


}


simply by adding these two lines:



}



Custom.UI.DropZoneBehavior.prototype = {


 


14. Throughout the rest of the prototype definition, refer to your variables as members by adding


this.

in front of all of them.


 


15. Interfaces have changed.  The bahavior class, which did not used to take a parameter, now does:



Custom.UI.FloatingBehavior = function(value) {
    Custom.UI.FloatingBehavior.initializeBase(this,[value]);

}

 


16. Properties and methods are written differently in the prototype definition than they were in closures.  Wherever you have a method or property, you should rewrite it by getting rid of the preceding “this.” and replacing the equals sign in your method definition with a colon.  Finally, a comma must be inserted after each method or property definition except the last.  For example, this:



this.initialize = function() {
    Custom.UI.FloatingBehavior.callBaseMethod(this, ‘initialize’);

}


becomes this:


 



initialize: function() {
     Custom.UI.FloatingBehavior.callBaseMethod(this, ‘initialize’);

},


 


17. Type descriptors are gone.  This means you no longer need the getDescriptor method or the Sys.TypeDescriptor.addType call to register your Type Descriptor.  There is an alternate grammar for writing type descriptors using JSON, but my code worked fine without it.  I think it is meant for writing extenders.


 


18. Hooking up event handlers to DOM events has been simplified.  You used to need to define a delegate for the DOM event, and then use the attachEvent and detachEvent methods to link the delegate with your handler function.  In the beta 2, all of this is encapsulated and you will only need two super functions, $addHandler and $removeHandler.  You should probably place your $addHandler method to your initialize method, and $removeHandler to your dispose method.  The syntax for $addHandler will typically look like this:


$addHandler(this.get_element(), ‘mousedown’, YourMouseDownHandlerFunction)

$removeHandler takes the same parameters.  One thing worth noting is that, whereas the reference to the DOM event used to use the IE specific event name, in this case ‘onmousedown’, the designers of ASP.Net Ajax have now opted to use the naming convention adopted by Firefox and Safari. 


 


19. The last touch: add the following lines as the last bit of code in your script file:



if(typeof(Sys) !== “undefined”)
Sys.Application.notifyScriptLoaded();


You basically just need to do this.  It may even be one of the rare instances in programming where you don’t even need to know why you are doing it since, as far as I know, you will never encounter a situation where you won’t put it in your script.  My vague understanding of the reason, though, is that the ASP.Net Ajax page lifecycle needs to know when scripts are loaded; both IE and Firefox throw events when a page has completed loading.  Safari, however, does not.  notifyScriptLoaded() provides a common way to let all browsers know when scripts have been loaded and it is safe to work with the included classes and functions.


 


 


Bibliography (of sorts):


Here are the good guides I referred to at the top of this post: Bertrand LeRoy‘s post on javascript prototypes, Eilon Lipton‘s blog, the comments here: Scott Guthrie, Sean Burke‘s migration guide, Miljan Braticevic‘s experience with upgrading the Component Art tools.  The most comprehensive guide to using Ajax Extensions beta 2 is actually the upgrade guide provided by Microsoft Ajax Team here: AspNet AJAX CTP to Beta Whitepaper. I used the official online documentation, http://ajax.asp.net/docs/Default.aspx, mainly to figure out which namespaces to use and where the various functions I needed had been moved to.  Finally, using the search functionality on the ASP.Net Ajax forums helped me get over many minor difficulties.

V. ASP.NET Ajax Imperative Dropzones


 


To create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior:


function addDropZoneBehavior(ctrl){

$create(Custom.UI.DropZoneBehavior, {}, null, null, ctrl);
}


To finish hooking everything up, call this addDropZoneBehavior function from the ASP.NET Ajax pageLoad() method, as you did in earlier examples for the addFloatingBehavior function.  This will attach the proper behaviors to their respective html elements and replicate the drag and dropzone functionality you created above using declarative markup.  If you want to make this work dynamically, just add the createDraggableDiv() function you already wrote for the previous dynamic example.  As a point of reference, here is the complete code for creating programmatic dropzones:



<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1″ runat=”server”>
<title>Imperative Drop Targets</title>
<script type=”text/javascript”>
    function addFloatingBehavior(ctrl, ctrlHandle){
        $create(Sys.Preview.UI.FloatingBehavior, {‘handle’: ctrlHandle}, null, null, ctrl);
    }
    function addDropZoneBehavior(ctrl){
        $create(Custom.UI.DropZoneBehavior, {}, null, null, ctrl);
    }
    function pageLoad(){
        addDropZoneBehavior($get(‘dropZone’));
        addFloatingBehavior($get(‘draggableDiv’),$get(‘handleBar’));
    }
</script>
</head>
<body>
<form id=”form1″ runat=”server”>
<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
    <Scripts>
            <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript” />
        <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop” />
        <asp:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
    </Scripts>
</asp:ScriptManager>
<h2>Imperative Drop Targets with javacript</h2>
<div style=”background-color:Red;height:200px;width:200px;”>
    <div id=”draggableDiv” style=”height:100px;width:100px;background-color:Blue;”>
        <div id=”handleBar” style=”height:20px;width:auto;background-color:Green;”>
        </div>
    </div>
</div>
<div id=”dropZone” style=”background-color:cornflowerblue;height:200px;width:200px;”>Drop Zone</div>
</form>
</body>
</html>

 

Conclusion


Besides the dropzone behavior, you may want to also write your own floating behavior. For instance, by default, elements decorated with the floating behavior simply stay where you drop them. You may want to extend this so that your floating div will snap back to its original location when you drop it outside of a drop zone. Additionally, you may want to change the way the dragged element looks while you are dragging it, either by making it transparent, changing its color, or replacing the drag image altogether. All this can be accomplished by creating a behavior that implements the IDragSource interface in the same way you created a custom class that implements the IDropTarget interface.


This tutorial is for the most part a straight translation of the original Atlas tutorial that I wrote against the April CTP.  Even though many of the concepts behind Atlas are still retained in Ajax Extensions, some have changed by a turning of the screw so that what was once fitting and accurate in the original tutorial is no longer quite so.  For instance, whereas in the original Atlas tutorial I could talk about Xml Scripting and the rest of the ASP.NET Ajax functionality as one technology, they are now currently two varying technologies with different levels of support and interest for Microsoft.  There are more subtle differences that, I think, make the current version of the tutorial somewhat dated, as if I am saying everthing with a slight accent; in other words, while I stand by the accuracy of this tutorial, I think it has lost some of its original elegance in the translation.  I believe the tutorial will still be useful for those trying to get started with Microsoft’s Ajax implementation, though it’s chief utility, at this point, will probably be for people who were used to the Atlas way of doing things and need a point of reference to see how the semantics of the technology has changed. I hope the samples will help you over some of your growing pains, as writing it has helped me with mine.

IV. ASP.NET Ajax Declarative Dropzones


 



Being able to drag html elements around a page and have them stay where you leave them is visually interesting. To make this behavior truly useful, though, an event should be thrown when the drop occurs.  Furthermore, the event that is thrown should depend on where the drop occurs.  In other words, there needs to be behavior that can be added to a given html element that will turn it into a “dropzone” or a “drop target”,  the same way that the floating behavior can be added to an html div tag to turn it into a drag and drop element.

In the following examples, I will show how Atlas supports the concept of dropzones.  In its current state, Atlas does not support an out-of-the-box behavior for creating dropzone elements in quite the same way it does for floating elements.  It does, however, implement behaviors for a dragdroplist element and a draggablelistitem element which, when used together, allow you to create lists that can be reordered by dragging and dropping.  If you would like to explore this functionality some more, there are several good examples of using the dragDropList behavior on the web, for instance, Introduction to Drag And Drop with Atlas.

The main disadvantage of the dragdropzone behavior is that it only works with items that have been decorated with the DragDropList behavior. The functionality that this puts at your disposal is fairly specific. To get the sort of open-ended dropzone functionality I described above, that will also work with the predefined floating behavior, you will need to write your own dropzone behavior class in JavaScript. Fortunately, this is not all that hard.


Atlas adds several OOP extensions to JavaScript in order to make it more powerful, extensions such as namespaces, abstract classes, and interfaces. You will take advantage of these in coding up your own dropzone behavior. If you peer behind the curtain and look at the source code in the PreviewDragDrop.js file, (contained in the directory C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\ScriptLibrary\Debug), you will find several interfaces defined there, including one for Sys.UI.DragSource and one for Sys.UI.DropTarget. In fact, both the FloatingBehavior class and the DraggableListItem class implement the Sys.UI.DragSource interface, while Sys.UI.DropTarget is implemented by the DragDropList class. The code for these two interfaces looks like this:



Sys.Preview.UI.IDragSource = function Sys$Preview$UI$IDragSource() {
}


Sys.Preview.UI.IDragSource.prototype = {
      get_dragDataType: Sys$Preview$UI$IDragSource$get_dragDataType,
      getDragData: Sys$Preview$UI$IDragSource$getDragData,
      get_dragMode: Sys$Preview$UI$IDragSource$get_dragMode,
      onDragStart: Sys$Preview$UI$IDragSource$onDragStart,
      onDrag: Sys$Preview$UI$IDragSource$onDrag,
      onDragEnd: Sys$Preview$UI$IDragSource$onDragEnd
}
Sys.Preview.UI.IDragSource.registerInterface(‘Sys.Preview.UI.IDragSource’);

Sys.Preview.UI.IDropTarget = function Sys$Preview$UI$IDropTarget() {
}


Sys.Preview.UI.IDropTarget.prototype = {
     get_dropTargetElement: Sys$Preview$UI$IDropTarget$get_dropTargetElement,
     canDrop: Sys$Preview$UI$IDropTarget$canDrop,
     drop: Sys$Preview$UI$IDropTarget$drop,
     onDragEnterTarget: Sys$Preview$UI$IDropTarget$onDragEnterTarget,
     onDragLeaveTarget: Sys$Preview$UI$IDropTarget$onDragLeaveTarget,
     onDragInTarget: Sys$Preview$UI$IDropTarget$onDragInTarget
}
Sys.Preview.UI.IDropTarget.registerInterface(‘Sys.Preview.UI.IDropTarget’);


Why do you need to implement these interfaces instead of simply writing out brand new classes to support drag, drop, and dropzones? The secret is that, behind the scenes, a third class, called the DragDropManager, is actually coordinating the interactions between the draggable elements and the dropzone elements, and it only knows how to work with classes that implement the IDragSource or the IDropTarget. The DragDropManager class registers which dropzones are legitimate targets for each draggable element, handles the MouseOver events to determine when a dropzone has a draggable element over it, and a hundred other things you do not want to do yourself. In fact, it does it so well that the dropzone behavior you are about to write is pretty minimal. First, create a new JavaScript file called DropZoneBehavior.js. I placed my JavaScript file under a subdirectory called scriptLibrary, but this is not necessary in order to make the dropzone behavior work. Next, copy the following code into your file:



Type.registerNamespace(‘Custom.UI’);
Custom.UI.DropZoneBehavior = function(value) {
 Custom.UI.DropZoneBehavior.initializeBase(this, [value]);


}


Custom.UI.DropZoneBehavior.prototype = {
    initialize:  function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘initialize’);
        // Register ourselves as a drop target.
        Sys.Preview.UI.DragDropManager.registerDropTarget(this);
        },
    dispose: function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘dispose’);
        },
    getDescriptor: function() {
        var td = Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘getDescriptor’);
        return td;
        },
    // IDropTarget members.
    get_dropTargetElement: function() {
        return this.get_element();
        },
    drop: function(dragMode, type, data) {
        alert(‘dropped’);
        },
    canDrop: function(dragMode, dataType) {
        return true;
        },
    onDragEnterTarget: function(dragMode, type, data) {
        },
    onDragLeaveTarget: function(dragMode, type, data) {
        },
    onDragInTarget: function(dragMode, type, data) {
        }
}
Custom.UI.DropZoneBehavior.registerClass(‘Custom.UI.DropZoneBehavior’, Sys.UI.Behavior, Sys.Preview.UI.IDragSource, Sys.Preview.UI.IDropTarget, Sys.IDisposable);
if(typeof(Sys) != “undefined”) {Sys.Application.notifyScriptLoaded();}



I need to explain this class a bit backwards.  The first thing worth noticing is the second to last line that begins “Custom.UI.DropZoneBehavior.registerClass.”  This is where the dropZoneBehaviorClass defined above gets registered with Ajax Extensions.  The first parameter of the registerClass method takes the name of the class.  The second parameter takes the base class.  The remaining parameters take the interfaces that are implemented by the new class.  The line following this throws a custom event indicating that the script has completed loading (this is needed in order to support Safari, which does not do this natively).  Now back to the top, the “Type.registerNamespace” method allows you to register your custom namespace.  The next line declares our new class using an anonymous method syntax.  This is a way of writing JavaScript that I am not particularly familiar with, but is very important for making JavaScript object oriented, and is essential for designing Atlas behaviors.  Within the anonymous method, the class methods initialize, dispose, and getDescriptor are simply standard methods used for all behavior classes, and in this implementation, all you need to do is call the base method (that is, the method of the base class that you specify in the second to last line of this code sample.)  The only thing special you do is to register the drop target with the Sys.Preview.UI.DragDropManager in the initialize method.  This is the act that makes much of the drag drop magic happen.

Next, you implement the IDropTarget methods.  In this example, you are only implementing two methods, “this.canDrop” and “this.drop”.  For “canDrop”, you are just going to return true.  More interesting logic can be placed here to determine which floating div tags can actually be dropped on a given target, and even to determine what sorts of floating divs will do what when they are dropped, but in this case you only want a bare-bones implementation of  IDropTarget that will allow any floating div to be dropped on it.   Your implementation of the “drop” method is similarly bare bones.  When a floating element is dropped on one of your drop targets, an alert message will be thrown indicating that something has occurred.  And that’s about it.  You now have a drop behavior that works with the floating behavior we used in the previous examples.

You should now write up a page to show off your new custom dropzone behavior.  You can build on the previous samples to accomplish this.  In the Script Manager, besides registering the PreviewDragDrop script, you will also want to register your new DropZoneBehavior script:



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
    <Scripts>
        <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript” />
        <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop” />
        <asp:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
    </Scripts>
</asp:ScriptManager>


Next, you will want to add a new div tag to the HTML body, that can be used as a drop target:



<div style=”background-color:Red;height:200px;width:200px;”>
    <div id=”draggableDiv” style=”height:100px;width:100px;background-color:Blue;”>
        <div id=”handleBar” style=”height:20px;width:auto;background-color:Green;”>
        </div>
    </div>
</div>
<div id=”dropZone” style=”background-color:cornflowerblue;height:200px;width:200px;”>
    Drop Zone
</div>


Finally, you need to add a declarative markup element to add your custom DropZone behavior to the div you plan to use as a dropzone element. The XML markup should look like this:



<script type=”text/xml-script”>
    <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″ xmlns:JavaScript=”Custom.UI”>
<components>
<control id=”dropZone”>
                <behaviors>
                    <JavaScript:DropZoneBehavior/>
                </behaviors>
            </control>
<control id=”draggableDiv”>
                <behaviors>
                    <floatingBehavior handle=”handleBar”/>
                </behaviors>
            </control>
        </components>
    </page>
</script>


The code you have just written should basically add a drop zone to the original declarative drag and drop example.  When you drop your drag element on the drop zone, an alert message should now appear.  You can expand on this code to make the drop method of your custom dropzone behavior do much more interesting things, such as firing off other javascript events in the current page or even calling a webservice, using ASP.NET Ajax, that will in turn process server-side code for you. 

III. ASP.NET Ajax Dynamic Drag and Drop


 



Since the declarative model is much cleaner than the imperative model, why would you ever want to write your own javascript to handle Ajax Extensions behaviors?  You might want to roll your own javascript if you want to add behaviors dynamically.  One limitation of the declarative model is that you can only work with objects that are initially on the page.  If you start adding objects to the page dynamically, you cannot add the floating behavior to them using the declarative model.  With the imperative model, on the other hand, you can.

Building on the previous example, you will replace the “pageLoad()” function with a function that creates floating divs on demand.  The following javascript function will create a div tag with another div tag embedded to use as a handlebar, then insert the div tag into the current page, and finally add floating behavior to the div tag:


function createDraggableDiv() {
var panel= document.createElement(“div”);
panel.style.height=“100px”;
panel.style.width=“100px”;
panel.style.backgroundColor=“Blue”;
var panelHandle = document.createElement(“div”);
panelHandle.style.height=“20px”;
panelHandle.style.width=“auto”;
panelHandle.style.backgroundColor=“Green”;
panel.appendChild(panelHandle);
var target = $get(‘containerDiv’).appendChild(panel);
addFloatingBehavior(panel, panelHandle);
}

You will then just need to add a button to the page that calls the “createDraggableDiv()” function. The new HTML body should look something like this:


<input type=”button” value=”Add Floating Div” onclick=”createDraggableDiv();” />
<div id=”containerDiv” style=”background-color:Purple;height:800px;width:600px;”/>

This will allow you to add as many draggable elements to your page as you like, thus demonstrating the power and flexibility available to you once you understand the relationship between using Ajax Extensions declaratively and using it programmatically.  As a point of reference, here is the complete code for the dynamic drag and drop example:



<%@ Page Language=”C#”  %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>Imperative Drag and Drop II</title>
<script type=”text/javascript”>
function createDraggableDiv() {
     var panel = document.createElement(“div”);
     panel.style.height=”100px”;
     panel.style.width=”100px”;
     panel.style.backgroundColor=”Blue”;
     var panelHandle = document.createElement(“div”);
     panelHandle.style.height=”20px”;
     panelHandle.style.width=”auto”;
     panelHandle.style.backgroundColor=”Green”;
     panel.appendChild(panelHandle);
     var target = $get(‘containerDiv’).appendChild(panel);
     addFloatingBehavior(panel, panelHandle);
     }
function addFloatingBehavior(ctrl, ctrlHandle){
     $create(Sys.Preview.UI.FloatingBehavior, {‘handle’: ctrlHandle}, null, null, ctrl);
     }
</script>
</head>
<body>
<form id=”form1″ runat=”server”>
<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
<Scripts>
        <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js” />
 <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js” />
</Scripts>
</asp:ScriptManager>
<h2>Imperative Drag and Drop Code with javascript: demonstrate dynamic loading of behaviors</h2>
<input type=”button” value=”Add Floating Div” onclick=”createDraggableDiv();” />
<div id=”containerDiv” style=”background-color:Purple;height:800px;width:600px;”/>
</form>
</body>
</html>

II. ASP.NET Ajax Imperative Drag and Drop


 



To accomplish the same thing using a programmatic model requires a bit more code, but not much more.  It is important to understand that when you add an Ajax Extensions Script Manager component to your page, you are actually giving instructions to have the Ajax Extensions javascript library loaded into your page.  The Ajax Extensions library, among other things, provides client-side classes that extend the DOM and provide you with tools that allow you to code in a browser agnostic manner (though there currently are still issues with Safari compatibility).  These client-side classes also allow you to add behaviors to your html elements.

To switch to an imperative model, you will need to replace the XML markup with two javascript functions.  The first one is generic script to add floating behavior to an html element.  It leverages the Ajax Extensions client-side classes to accomplish this:



<script type=”text/javascript”>
        function addFloatingBehavior(ctrl, ctrlHandle){
              $create(Sys.Preview.UI.FloatingBehavior, {‘handle’: ctrlHandle}, null, null, ctrl);


              }
</script>



The function takes two parameter values; the html element that you want to make draggable, and the html element that is the drag handle for the dragging behavior.  The new $create function encapsulates the instantiation and initialization routines for the behavior.  The addFloatingBehavior utility function will be used throughout the rest of this tutorial.

Now you need to call the “addFloatingBehavior” function when the page loads.  This, surprisingly, was the hardest part about coding this example.  The Script Manager doesn’t simply create a reference to the Ajax Extensions javascript libraries, and I have read speculation that it actually loads the library scripts into the DOM.  In any case, what this means is that the libraries get loaded only after everything else on the page is loaded.  The problem for us, then, is that there is no standard way to make our code that adds the floating behavior run after the libraries are loaded; and if we try to run it before the libraries are loaded, we simply generate javascript errors, since all of the Ajax Extensions methods we call can’t be found.

There are actually a few workarounds for this, but the easiest one is to use a custom Ajax Extensions event called “pageLoad()” that  only gets called after the libraries are loaded.  To add the floating behavior to your div tag when the page is first loaded (but after the library scripts are loaded) you just need to write the following:


<script type=“text/javascript”>
function pageLoad(){
addFloatingBehavior(document.getElementById(‘draggableDiv’),
document.getElementById(‘handleBar’));
}
</script>

which, in turn, can be written this way, using an Ajax Extensions scripting shorthand that replaces “document.getElementById()” with “$get()“:


<script type=“text/javascript”>
function pageLoad(){
addFloatingBehavior($get(‘draggableDiv’),$get(‘handleBar’));
}
</script>

And once again, you have a draggable div that behaves exactly the same as the draggable div you wrote using the declarative model.

I. ASP.NET Ajax Declarative Drag and Drop

 


The first task is to use XML markup to add drag-drop behavior to a div tag. By drag and drop, I just mean the ability to drag an object and the have it stay wherever you place it.  The more complicated behavior of making an object actually do something when it is dropped on a specified drop target will be addressed later in this tutorial.  To configure your webpage to use ASP.NET Ajax, you will need to install the Microsoft.Web.Extensions.dll into your Global Assembly Cache.  You will also need a reference to the library Microsoft.Web.Preview.dll.  Finally, you will need to configure your web.config file with the following entry:



<system.web>
    <pages>
        <controls>
            <add tagPrefix=”asp” namespace=”Microsoft.Web.UI” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral,  PublicKeyToken=31bf3856ad364e35″ />
            <add tagPrefix=”asp” namespace=”Microsoft.Web.UI.Controls” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
            <add tagPrefix=”asp” namespace=”Microsoft.Web.Preview.UI” assembly=”Microsoft.Web.Preview” />
        </controls>
    </pages>
</system.web>


You will need to add an Atlas Script Manager control to your .aspx page and configure it to use the PreviewDragDrop library file:



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
    <Scripts>
        <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js” />
 <asp:ScriptReference Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js” />
    </Scripts>
</asp:ScriptManager>


Add the div object you want to make draggable, and make sure it has a drag handle:



<div style=”background-color:Red;height:800px;width:600px;”>
    <div id=”draggableDiv” style=”height:100px;width:100px;background-color:Blue;”>
        <div id=”handleBar” style=”height:20px;width:auto;background-color:Green;”>
        </div>
    </div>
</div>


Finally, add the markup script that will make your div draggable:



<script type=”text/xml-script”>
    <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″>
        <components>
            <control id=”draggableDiv”>
                <behaviors>
                    <floatingBehavior handle=”handleBar”/>
                </behaviors>
            </control>
        </components>
    </page>
</script>


And with that, you should have a draggable div tag.  The example demonstrates the simplicity and ease of using the declarative model with Ajax Extensions.  In the terminology being introduced with Ajax Futures, you have just used declarative markup to add the floating behavior to an html element.

Microsoft ASP.NET Ajax Drag and Drop Tutorial



Beta 2 Source Code

RC Source Code (Web Project)

July 2007 Futures CTP (Web Project)


2007 Update


The linked zip files above have been updated for the July 2007 CTP of AJAX Futures. The only breaking change worth noting between the AJAX Futures beta and later CTPs is that the syntax for ScriptReferences in the ScriptManager and ScriptManagerProxy has changed.

Whereas in the beta, you would have written:

     <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js" />   
            <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js" />   
        </Scripts>
     </asp:ScriptManager>

you now should use the shortened form:

     <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="PreviewScript.js" />   
            <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="PreviewDragDrop.js" />   
        </Scripts>
     </asp:ScriptManager>

Preface


The hardworking Atlas/Ajax team has greatly improved the architecture of the Ajax Extensions framework with the Beta 2, making it much more rational and easy to use for future adopters. Sadly, for us early adopters, this also meant a large number of breaking changes and a bit of a struggle trying to figure out the new paradigms for programming ASP.NET.  At this point in time, the documentation hasn’t yet caught up with the innovation, and so the best place to look for reliable information about how to use ASP.Net is to go the professional blogs of the various Microsoft developers: Bertrand LeRoy, Eilon Lipton, Scott Guthrie.  The blog of Miljan Braticevic of Component Art was also extremely helpful.  Greatest thanks to mavenger00 at www.codeproject.com, who got me over a major pain point and found an error in the official xml script documentation that no one else seems to have.  While the upgrade of this tutorial was a little painful, it was also instructive.  The only thing I think I don’t like about the new Beta 2 is the rebranding of Atlas — “Atlas” was a much more convenient moniker, and at this point I’m not totally sure when or how to use the terms ASP.NET Ajax, Ajax Extensions, Ajax Futures, etc.  I do my best to scatter them about randomly and interchangeably to give a false sense of authoritativeness.

Introduction


This tutorial is intended to help readers understand how certain aspects of Microsoft’s new Ajax Extensions technology works. Ajax Extensions is intended to simplify the development of Ajax-style functionality.  As with all technology, however, to use a tool well, it is important to understand the underlying technology that Atlas abstracts.  One of the key ASP.NET Ajax abstractions is the new XML markup syntax developed to make coding with Ajax easier (originally included with the core Atlas files, XML markup is now a part of the CTP called Ajax Futures).  With XML markup, developers can modify their code declaratively.  However, there are times when a developer may want to be able to change her code programmatically, and in order to accomplish this, she will need to understand that underneath the markup abstraction, she is actually dealing with good ‘ol javascript and some custom javascript libraries developed by Microsoft.  In order to demonstrate the relationship between the Atlas declarative model and the programmatic model, I will go through a series of examples in which the same task will be accomplished both declaratively and programmatically.  I will be demonstrating how to use the PreviewDragDrop library file to perform basic drag-drop operations as well as setting up drop zones. 


Background


As I write this, Microsoft has made some important changes to ASP.NET Ajax for the Beta 2 that have the unfortunate side-effect of breaking most of the original Atlas implementation, and has required a bit of rework of the original samples.  These revised examples apply to the Beta 2 of ASP.NET Ajax. Future releases of Ajax Extensions may affect the accuracy of this tutorial.  I will attempt to update the code as new versions of Ajax Extensions become available.  Ajax Extensions works with .Net 2.0 and will work with Orcas when it is released.

Technological Similes (e.g., Ajax is like…)


 As mentioned in a previous post, programmers typically explain one technology by referencing another more familiar technology.  What sometimes happens, however, is that the technology that was thought to be more familiar, and consequently believed to have explanatory power, in fact was simply originally explained by referencing some third vaguely understood technology; but time made the simile comfortable and vanity made it acceptable.  We only become aware of the semantic web we programmers weave when we are finally forced to use one of the referenced technologies and discover, once again, what a strange and incomprehensible thing programming is.  The experience is a bit like the shock felt by the woman who brought home a stray dog from Paris only to discover that it was really a large tailless rat.


To find out what one of the trendier new technologies is really like, I recently consulted Google.  A google search on “Ajax is like…” turns up the following results:



“Comparing Java and AJAX is like comparing apples and blue.”


“[U]sing Ajax is like consuming alcohol in public.”


“[A]jax is like instant messaging….”


“Customers asking for AJAX is like a prospective homeowner walking over to the contractors hired to do the building and handing them a saw.”


“AJAX is like Flash or HTML.”


“AJAX is like a javascript.”


“AJAX is like Javascript on steroids.”


“AJAX is like web services.”


“[A]jax is like everything else on line, it will be abused by various low lifes.”


“Ajax is like to partial update in Intraweb I am wrong?”


“Ajax is like ‘roller skates for the web.'”


“Ajax is like shell, Perl, Ruby. Ajax is like UNIX.”


“AJAX is like a Hooker turn School Teacher, it has a dirty secret and unless you get it alone and play with it, you won’t pickup on it’s secrets until it’s too late.”


“Ajax is, like stated in the essay, a new way to think about user interfaces on the web….”


“AJAX is like wearing 70’s djeans with an Hugo Boss Shoes….”


“AJAX is like Dinosaur cloning in Jurassic park.”


“AJAX is like folding a web page origami-style into a Lego brick….”


“AJAX is like a house of cards, and when a browser vendor screws up on a revision it’ll all come tumbling down.”


“AJAX is like putting a tiny bandage on a gaping wound the size of a grapefruit.”


“Ajax is like DHTML was 4 years ago, like javascript was 6 years ago, like applets were 8 years ago.”


“AJAX is like the killer buzzword.”


V. Imperative Dropzones


 


To create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior:


function addDropZoneBehavior(ctrl){
var dropZone = new Sys.UI.Control(ctrl);
var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
dropZone.get_behaviors().add(dropZoneBehavior);
dropZoneBehavior.initialize();
}

To finish hooking everything up, call this addDropZoneBehavior function from the Atlas pageLoad() method, as you did in earlier examples for the addFloatingBehavior function. This will attach the proper behaviors to their respective HTML elements and replicate the drag and dropzone functionality you created above using declarative markup. If you want to make this work dynamically, just add the createDraggableDiv() function you already wrote for the previous dynamic example. As a point of reference, here is the complete code for creating programmatic dropzones:


<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1″ runat=”server”>
<title>Imperative Drop Targets</title>
<script type=”text/javascript”>
function addFloatingBehavior(ctrl, ctrlHandle){
var floatingBehavior = new Sys.UI.FloatingBehavior();
floatingBehavior.set_handle(ctrlHandle);
var dragItem = new Sys.UI.Control(ctrl);
dragItem.get_behaviors().add(floatingBehavior);
floatingBehavior.initialize();
}
function addDropZoneBehavior(ctrl){
var dropZone = new Sys.UI.Control(ctrl);
var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
dropZone.get_behaviors().add(dropZoneBehavior);
dropZoneBehavior.initialize();
}
 
function pageLoad(){
addDropZoneBehavior($(‘dropZone’));
addFloatingBehavior($(‘draggableDiv’),$(‘handleBar’));
}
</script>
</head>
<body>
<form id=”form1″ runat=”server”>
<atlas:ScriptManager ID=”ScriptManager1″ runat=”server”>
<Scripts>
<atlas:ScriptReference ScriptName=”AtlasUIDragDrop” />
<atlas:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
</Scripts>
</atlas:ScriptManager>
<h2>Imperative Drop Targets with javacript</h2>
<div style=”background-color:Red;height:200px;width:200px;”>
<div id=”draggableDiv”
style=”height:100px;width:100px;background-color:Blue;”>
<div id=”handleBar”
style=”height:20px;width:auto;background-color:Green;”>
</div>
</div>
</div>
<div id=”dropZone” style=”background-color:cornflowerblue;
height:200px;width:200px;”>Drop Zone</div>
</form>
</body>
</html>
 

Conclusion


Besides the dropzone behavior, you may want to also write your own floating behavior. For instance, by default, elements decorated with the floating behavior simply stay where you drop them. You may want to extend this so that your floating div will snap back to its original location when you drop it outside of a drop zone. Additionally, you may want to change the way the dragged element looks while you are dragging it, either by making it transparent, changing its color, or replacing the drag image altogether. All this can be accomplished by creating a behavior that implements the IDragSource interface in the same way you created a custom class that implements the IDropTarget interface.


This tutorial should provide you with a starting point for extending the basic drag drop functionality provided with Atlas, to create your own behaviors and provide your own functionality. The next step is to build on this to create controls. Using this tutorial as a starting point, you can go on to create Atlas extender controls that implement your behaviors using declarative markup, or even turn around and create server-side controls that automatically create HTML elements with Atlas behaviors, with the choice being, once again, one between creating server-side controls that are either declarative, and consequently static, or imperative, and consequently slightly more complex but also more flexible. This is a topic that is much too large for the current tutorial; however, I hope that in the near future, someone will try to do for server-side Atlas programming what this tutorial attempts to do for client-side Atlas scripting.