Drag and Drop Programming in Microsoft ASP.NET AJAX

Nowadays AJAX has attracted more and more developers. Microsoft ASP.NET AJAX 1.0 (MS AJAX), a young yet excellent open source AJAX framework provided mainly by Microsoft, certainly attracts developers with its whole solution on both the server side and client side. In this article, we’ll first summarize the multiple solutions suggested by MS AJAX, and then explore a general yet rather complex sample which in fact reflects the under-the-hood workings of all the client side drag and drop solutions within the MS AJAX framework.


A downloadable .rar file is available for this article.

Introduction

 

 

Author’s Note: First, as far as the MS AJAX framework is concerned, it is generally referred to as the three components below:

  • ASP.NET AJAX Extensions, which corresponds to two assemblies, System.Web.Extensions.dll and System.Web.Extensions.Design.dll, with three files, MicrosoftAjax.js, MicrosoftAjaxTimer.js, and MicrosoftAjaxWebForms.js contained within them;
  • ASP.NET AJAX Control Toolkit, which provides both ready-to-run samples and a powerful SDK to simplify creating custom ASP.NET AJAX controls and extenders; and
  • ASP.NET AJAX Futures January CTP (recently replaced by a May release, with the January one still available), which corresponds to the assembly Microsoft.Web.Preview.dll which contains three files: PreviewScript.js, PreviewGlitz.js, and PreviewDragDrop.js.

Second, to follow along with all the samples in this article, you’re assumed to have installed Visual Studio 2005, and all three components of MS AJAX above. In addition, it is suggested that you download the source files accompanying this article.

 

Various kinds of drag and drop solutions provided by MS AJAX

Since the drag and drop operation is increasingly becoming one of the most attractive features of nearly every web 2.0 site, MS AJAX has also provided many controls associated with drag and drop support from the server side to the client side. In this article, for brevity, we only summarize the related solutions as much as possible and give them a brief comparison in table form (see Table 1).

Position

Name

Features

Server side

DragOverlayExtender

Note that in the newest Futures CTP, this control is not explicitly contained within the PreviewScript.js file, but you can still find it inside the Microsoft.Web.Preview.dll assembly using the .NET Object Browser. This control provides only the dragging function without dropping support, which means that you can drag it wherever you want but without a special position to drop onto, not to mention the custom function. I’ve provided a sample web page named DragOverlayExtenderDemo.aspx in the source code with this article.

DragPanelExtender

When you use the DragOverlayExtender control, you can drag any position of the target. However, users often need to select the text within the control by dragging, which obviously conflicts with the general dragging operation so that users are deprived of the normal right of selecting text. The practical way to drag involves dragging some special area of the target as with the common Windows dragging operation. The DragPanelExtender control in the ASP.NET AJAX Control Toolkit provides just this function but with little extensibility and availability. In the source code I’ve also supplied a related demo of it (the DragPanelDemo.aspx page) for you to refer to.

ReorderList

Inside the ASP.NET AJAX Control Toolkit. This address provides you with a good example (I’ve tested it successfully). Compared with the above two controls, this control provides more functions and is more extensible. However, when we want to drag items among more than two controls of this kind, it’s quite difficult to make it work.

WebParts

This in fact refers to a group of related server-side controls – WebPartManager, WebPartZone, CatalogZone, EditorZone, etc. — with which you can easily build a web site much like Windows Live Spaces which enables end users to open, close, minimize, maximize or drag the customized gadgets on the page. Since now there are many samples with these controls, we won’t dwell on them further.

Client side

DragDropList

This control stays within the  PreviewDragDrop.js file (in ASP.NET AJAX Futures CTP). This address provides you with a good example (I’ve tested it successfully).

Thanks to its functions being totally implemented on the client side, the performance of the server side has been improved. With its rich functions you can even achieve the same effects as those of the WebParts; however, it lacks good extensibility and it is difficult to make the dragging result persist.

WebParts

Also shipped with ASP.NET AJAX Futures CTP, there is a PreviewWebParts.js file which aims to simulate the server side WebPart action. Despite the good drag and drop support and many other strong points, the server side WebParts still has two fatal limitations:

  • only supports IE;
  • Every time users change the gadget’s position, the current page will automatically trigger a post back to the server to persist the current configuration.

The first problem can be solved using the client side WebParts in ASP.NET AJAX Futures CTP, while the second can be overcome with the famous UpdatePanel control. All of these were well done in the former ASP.NET AJAX CTP version, but in the current Futures CTP these problems crop up, making a programmer’s life more difficult. Why??

IDragSource and IDropTarget

This is the most complicated client side drag and drop solution supplied by MS AJAX. In fact, the above DragDropList has just utilized this approach by implementing the interfaces IDragSource and IDropTarget; it, however, has just scratched the surface of this powerful approach. In the next section, we’ll further explore the underground mechanism of this solution.

{mospagebreak title=Inner workings of the client side drag and drop in MS AJAX}

In this section, we’ll explore the inner workings of the amazing cross-browser drag and drop client side support provided by MS AJAX. In general, when we build a UI supporting drag and drop there are the following points for us to consider:

  • Draggable items. Draggable items are DOM elements that can be moved around the page, while drop targets are elements that act as "containers" for draggable items. The MS AJAX framework allows us to define draggable elements by implementing the IDragSource interface.
  • Drop targets. A drop target is a class that implements the IDropTarget interface. Certainly, you can also create a class that implements both the IDragSource and the IDropTarget interfaces.
  • A DragDropManager. The DragDropManager is a global object instantiated at runtime, which is generally used to launch dragging operations and to register drop targets. As you may have figured out, the DragDropManager serves as the headquarters of the whole drag and drop operation by invoking the corresponding methods of the IDragSource and IDropTarget interfaces.

Thus, we can take the following steps to create a drag and drop UI:

  • Create draggable items by implementing the IDragSource interface. The class that implements this interface is also responsible for calling the Web.UI.DragDropManager.startDragDrop() method to start the dragging operation (typically, this is done in an event handler for the mousedown event of the control’s element). Each draggable item has its own dataType, which is an identifier that allows the grouping of draggable items (the predefined dataType is HTML);
  • Create drop targets by implementing the IDropTarget interface. A class that implements this interface is responsible for registering the drop target by invoking the Web.UI.DragDropManager.registerDropTarget() method. Each drop target has a list of acceptedDataTypes which specifies which "types" of draggable items can be dropped on that target.

Build a sample: an online shopping cart

In this sample, we’ll simulate the shopping cart component of an online pet store. The customers can choose and drag their selected commodities (which refer to pets here) onto the shopping cart, and when they finally decide to buy them, they can conveniently click the related ‘Order’ button near the shopping cart to preview all the item-related info in the shopping cart before going to the check counter.

{mospagebreak title=Create an ASP.NET AJAX CTP-Enabled Web Site}

Launch Visual Studio 2005 and then select the menu item "File | New Website…" to create a new website using the template named "ASP.NET AJAX CTP-Enabled Web Site," and name the project MSAJAXShoppingCar (select Visual C# as the built-in language). After that, the system should automatically add references to the necessary assemblies — Microsoft.Web.Preview.dll and System.Web.Extensions.dll. You will also see a ScriptManager server control automatically added to the page. Simply put, this server control acts as the controlling centre of the whole ASP.NET AJAX framework.

Next, with a little modification, page Default.aspx finally looks like the following Figure 1 (whose behind coding is discussed later).

Figure 1 the design-time snapshot of the online pet store

In this sample, when the application launches from the server side, all the commodity information (here it refers to the pets) is displayed on the web page automatically fetched from the server side web service (which is of course done in the AJAX way — asynchronously).

Figure 2 shows the run-time snapshot of the demo. Here the customer can click the item he would like to purchase and then just drag it onto the shopping cart nearby (as indicated by the red arrow).

Figure 2 the run-time snapshot of the online pet store

Just click the "Order" button near the shopping cart and you will be returned the final shopping invoice. Here lies a typical procession — when the buyer clicks the button, the application will invoke the underground Web Service with the information related to the selected items and finally the result data are shown to the buyer, as you can see in Figure 3.

Figure 3-the final snapshot after the customer click button ‘Order’

Now, since we have browsed to our finish line, let’s start the real work of creating the Web Service.

{mospagebreak title=Write the Web Service}

By using Web Service, we can utilize the standard way to wrap the basic database operation and supply the data to the client side. Right click the project, choose "Add new item" and create a new Web Service named ShoppingService.asmx. Next, we will open the ShoppingService.cs file and create the required web methods.

First, as required by the framework, we must put the ScriptService attribute before the Web Service so that the MS AJAX JavaScript framework can call it correctly. The following is the key code snippet:

 

[System.Web.Script.Services.ScriptService]

public class ShoppingService : System.Web.Services.WebService

 

Next, we should define a private field, Pets, to represent all the pet information in the online store:

 

private List<Pet> _pets;

private List<Pet> Pets

{

   get

   {

     if (_pets == null)

     {

       _pets = new List<Pet>();

       _pets.Add(new Pet(1, "Flex", "Cat","Gray",390));

       _pets.Add(new Pet(2, "Fido", "Dog", "Brown", 490));

       _pets.Add(new Pet(3, "Rover", "Dog", "Brown", 550));

       _pets.Add(new Pet(4, "Daisy", "Dog", "Black and White", 390));

       _pets.Add(new Pet(5, "Polly", "Cat", "Green", 490));

     }

     return _pets;

   }

}

 

Note here, just for the purposes of the demo, we’ve hard coded some commodities instead of inquiring for the information from the database. In real world scenarios, this kind of data is typically acquired from inside some database.

Next, we are to define the Pet class as an OOP wrapper of the pet information, with the fields called Id, Name and Price representing the identification, name and price properties of the pet, respectively:

 

public class Pet

{

   private int _id;

   public int Id

   {

     get { return _id; }

     set { _id = value; }

   }

   private string _name;

   public string Name

   {

     get { return _name; }

     set { _name = value; }

   }

   private int _category;

   public int Category

   {

     get { return _category; }

     set { _category = value; }

   }

   private int _color;

   public int Color

   {

     get { return _color; }

     set { _color = value; }

   }

   private int _price;

   public int Price

   {

     get { return _price; }

     set { _price = value; }

   }

   public Pet()

   {

   }

   public Pet(int id, string name, string category, string color, int price)

   {

     this._id = id;

     this._name = name;

     this._category = category;

     this._color = color;

     this._price = price;

   }

}

 

From now on, we’ll define the necessary WebMethods. The first one named GetPets() is used to return all current commodities stored in the warehouse:

 

[WebMethod]

public Pet[] GetPets()

{

   return Pets.ToArray();

}

 

As is hinted from the above figures, we should also define a WebMethod named Order which is used to process pet information posted from the client side shopping cart and then return the final result. Here, the one parameter of the Order method is a Dictionary structure; the Key corresponds to the Id of the pet and Value to the number of the selected pet inside the shopping cart:

 

[WebMethod]

public string Order(Dictionary<string, int> petsToBeOrdered)

{

   // total number of pets

   int totalQuantity = 0;

   // total price of pets

   int totalPrice = 0;

   //figure out the total price of all the pets to buy

   foreach (KeyValuePair<string, int> petQuantity in petsToBeOrdered)

   {

     foreach (Pet pet in Pets)

     {

       if (pet.Id.ToString() == petQuantity.Key)

       {

         totalQuantity += petQuantity.Value;

         totalPrice += (pet.Price * petQuantity.Value);

         break;

       }

     }

   }

   //return the dealt result

   return string.Format(

     "You’ve ordered {0} pet(s) at the total price {1}. Thank you!",

     totalQuantity,

     totalPrice

   );

}

 

That’s all we have room for right now. In the second part, we will look at the really interesting aspects — defining the drag and drop behaviors to achieve our goal. You won’t want to miss it!

Join the conversation
about this article

View thread