Introduction
This tutorial is intended to explain quickly how to implement drag and drop using the ASP.NET 2.0 AJAX Futures November CTP. To explain this technology, I've created a simple project with a custom AJAX control that implements a jigsaw puzzle game.
Background
When I started to learn the new ASP.NET AJAX framework, I asked my company to buy a book, and I chose an amazing book:
In this book, I found a chapter that explains how to use the PreviewDragDrop
to implement drag and drop on web. I used this chapter and other information from Internet (Google) to create my AJAX control.
The ASP.NET AJAX Framework
The basic idea within the ASP.NET AJAX Framework is to have a possibility to use object-oriented programming in JavaScript (simulated OOP) and make it similar to C#. Most C# features are available in JavaScript: namespace, class, interface, enum etc. Besides the OOP features is available the possibility to implement visual custom controls (client side controls) that extend the HTML elements' functionalities.
Basically, we have two types of controls (visual controls):
- Behavior (extending
Sys.UI.Behavior
) - Control (extending
Sys.UI.Control
)
The difference is just logic, but whilst generally Sys.UI.Behavior
is used to extend HTML element behaviors for different types of elements, Sys.UI.Control
is used to extend HTML element behaviors for a single type of element.
For example, if we want to implement a behavior that shows an alert on the click event, we can create a class that extends Sys.UI.Behavior
, and then we can use this code with several HTML element types: DIV
, SPAN
, INPUT
etc.
Type.registerNamespace("MyNamespace");
MyNamespace.MyBehavior = function(element)
{
MyNamespace.MyBehavior.initializeBase(this, [element]);
}
MyNamespace.MyBehavior.prototype =
{
initialize : function()
{
$addHandlers(this.get_element(), { "click" : this._onClick }, this);
},
dispose : function()
{
$clearHandlers(this.get_element());
},
_onClick : function(evt)
{
alert(this.get_id());
}
};
MyNamespace.MyBehavior.registerClass("MyNamespace.MyBehavior", Sys.UI.Behavior);
When we need to use it within our page, we can just write the following code:
$create(MyNamespace.MyBehavior, {}, {}, {}, $get('elementId'));
If we need to implement behaviors for an element type or we need to implement a complex control (a visual control composed of different elements), we need to extend Sys.UI.Control
.
AJAX Enabled Server Control
Generally, control are not manually created using $create
in JavaScript, but automatically generated by an ASP.NET Server Control (server side version of the control). This way, we can implement a server control and have design-time support within Visual Studio. When we want to create a AJAX enabled Server Control, we need to extend ScriptControl
(instead of WebControl
). This base class contains all methods useful to make a relation between the client control (JavaScript) and the server control (.NET).
In ScriptControl
, we need to override two methods:
GetScriptDescriptors
: pass the name of the JavaScript class and the properties to the client control.GetScriptReferences
: pass the scripts used by our client control. (The ScriptManager
automatically loads these scripts during page load).
protected override IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
{
if (!string.IsNullOrEmpty(this.Filename))
{
ScriptControlDescriptor descriptor = new
ScriptControlDescriptor("JigsawPuzzleGameControl.PuzzleGameAjax",
this.ClientID);
descriptor.AddProperty("nRows", this.NRows);
descriptor.AddProperty("nColumns", this.NColumns);
yield return descriptor;
}
}
protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
{
if (!string.IsNullOrEmpty(this.Filename))
{
List<ScriptReference> scripts = new List<ScriptReference>();
ScriptReference scriptReference1 = new ScriptReference("PreviewScript.js",
"Microsoft.Web.Preview");
scripts.Add(scriptReference1);
ScriptReference scriptReference2 = new ScriptReference("PreviewDragDrop.js",
"Microsoft.Web.Preview");
scripts.Add(scriptReference2);
ScriptReference scriptReference3 = new ScriptReference();
scriptReference3.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(),
"JigsawPuzzleGameControl.Resources.Helpers.js");
scripts.Add(scriptReference3);
ScriptReference scriptReference4 = new ScriptReference();
scriptReference4.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(),
"JigsawPuzzleGameControl.Resources.PuzzleGameAjax.js");
scripts.Add(scriptReference4);
return scripts;
}
else
{
return new List<ScriptReference>();
}
}
Drag and Drop
To implement drag and drop in our control, we need to implement two interfaces within two client controls:
- Client control that extends
Sys.Preview.UI.IDropTarget
: This control represents the drop area - Client control that extends
Sys.Preview.UI.IDragSource
: This control represents the drag element
In Sys.Preview.UI.IDropTarget
, we need to implements the following methods:
get_dropTargetElement
: return the HTML element of the drop areacanDrop
: check if drop is available for a particular drag elementdrop
: execute the drop actiononDragEnterTarget
: normally used with onDragLeaveTarget
to implement the visual effectonDragLeaveTarget
: normally used with onDragEnterTarget
to implement the visual effect
We also need to add an event handler within the method Initialize
for the MouseDown
event and then call Sys.Preview.UI.DragDropManager.startDragDrop
:
initialize : function()
{
JigsawPuzzleGameControl.DragPuzzleGameAjaxElement.callBaseMethod(this,
"initialize");
$addHandlers(this.get_element(),
{ "mousedown" : this._onMouseDown }, this);
},
_onMouseDown : function(evt)
{
window._event = evt;
evt.preventDefault();
Sys.Preview.UI.DragDropManager.startDragDrop(this,
this.get_element(), null);
},
In Sys.Preview.UI.IDragSource
, we need to implement the following methods:
get_dragDataType
: return the type of the drag element (the string used in canDrop
to check if the drag item is compatible with the drop area)getDragData
: return data that drags the item and passes to the drop area (drop method)get_dragMode
: return if the drag operation is Move
or Copy
onDragStart
: is called when the drag operation startsonDragEnd
: is called when the drag operation endsonDrag
: is called when the drag operation is completed
We also need to register and unregister the client component as the drop area:
initialize : function()
{
JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "initialize");
Sys.Preview.UI.DragDropManager.registerDropTarget(this);
},
dispose : function()
{
Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);
JigsawPuzzleGameControl.DropPuzzleGameAjaxElement.callBaseMethod(this, "dispose");
},
The Game
The project is divided into two projects:
- A web site containing an example of using the control
- A library project containing the control
Within the library project is a class called PuzzleGameAjax
that extends ScriptControl
(the base class for all custom controls in AJAX). This class is the server side code of my control.
On the client side, we have three JavaScript classes:
PuzzleGameAjax
(contains code to implement the game)DropPuzzleGameAjaxElement
(contains code to implement a drop area)DragPuzzleGameAjaxElement
(contains code to implement a drag area)
DropPuzzleGameAjaxElement
implements the Sys.Preview.UI.IDropTarget
interface and DragPuzzleGameAjaxElement
implements the Sys.Preview.UI.IDragSource
interface. These two interfaces are used by the AJAX framework to handle the drag and drop in a generic way.
Points of Interest
AJAX ASP.NET is a very good technology, and I'm currently working with it to implement a very complex behavior to improve the user experience. The drag and drop feature is absolutely the most user friendly feature, and it makes a software very intuitive to use. Normally, on web, this feature takes a lot of JavaScript code, but with PreviewDragDrop
, everything is easy.
History
- 30 March 2008 - First release (very poor to be honest, but I wanted to make it better!).
- 06 April 2008 - I made the article more complete.
- 08 April 2008 - Fixed a problem within the solution.
- 09 April 2008 - Now works with Visual Studio 2005/2008 (Express Edition included).
- 22 April 2008 - Added online demo.