Delving Deeper into Drag and Drop Programming in Microsoft ASP.NET AJAX

In the first part of this article, we summarized the multiple solutions suggested by MS AJAX, and began building an example to show some of these solutions in action. In the conclusion, we continue exploring this rather complex example to show you the under-the-hood workings of all the client side drag and drop solutions within the MS AJAX framework.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 8
June 25, 2007
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

A downloadable .rar file is available for this article.

Define a Behavior: DraggableProductBehavior to drag the product

With the analysis I gave you before, you can see that this DraggableProductBehavior is virtually a class that has to implement the Sys.Preview.UI.IDragSource interface. We'll attach this behavior to the related HTML DOM element that identifies the product to make it draggable.

Now, just create a new JavaScript file named ShoppingCart.js, and we should register the namespace ShoppingCartNamespace:

 

Type.registerNamespace("ShoppingCartNamespace");

 

Next, define the constructor of this class, as well as some necessary fields:

 

ShoppingCartNamespace.DraggableProductBehavior = function(element) {

  // initialize the base class

  ShoppingCartNamespace.DraggableProductBehavior.initializeBase(this, [element]);

  // the event handler for mouse down

  this._mouseDownHandler = Function.createDelegate(this, this._handleMouseDown);

 

  // the pet represented by the draggable object

  this._pet = null;

 

  // the translucent element(s) dragged with the mouse moving

  this._visual = null;

}

 

Next comes the prototype definition of the DraggableProductBehavior class:

 

ShoppingCartNamespace.DraggableProductBehavior.prototype = {

  //methods within interface IDragSource

  // return the data type of the draggable object--"Pet"

  get_dragDataType: function() {

    return "Pet";

  },

  // Obtain data from the draggable object

  getDragData: function(context) {

    return this._pet;

  },

  // Set the mode of the draggable object

  get_dragMode: function() {

    return Sys.Preview.UI.DragMode.Copy;

  },

  //call it when the dragging starts

  onDragStart: function() {

  },

  //call it when the dragging is going on

  onDrag: function() {

  },

  //call it when the dragging is over

  onDragEnd: function(canceled) {

    if (this._visual)

      this.get_element().parentNode.removeChild(this._visual);

  },

  //property pet

  get_product: function(pet) {

    return this._pet;

  },

  set_pet: function(pet) {

    this._pet = pet;

  },

  // initialize

  initialize: function() {

    $addHandler(this.get_element(), "mousedown", this._mouseDownHandler);

  },

  // mousedown event handler

  _handleMouseDown: function(ev) {

    // DragDropManager need this

    window._event = ev;

    //set the style of the translucent element(s) dragged with the mouse moving

    this._visual = this.get_element().cloneNode(true);

    this._visual.style.opacity = "0.7";

    this._visual.style.filter =

      "progid:DXImageTransform.Microsoft.BasicImage(opacity=0.7)";

    this._visual.style.zIndex = 99999;

    this.get_element().parentNode.appendChild(this._visual);

    var location = Sys.UI.DomElement.getLocation(this.get_element());

    Sys.UI.DomElement.setLocation(this._visual, location.x, location.y);

    //notify the DragDropManager that the dragging has started

    Sys.Preview.UI.DragDropManager.startDragDrop(this, this._visual, null);

  },

  //destructor

  dispose: function() {

    if (this._mouseDownHandler)

      $removeHandler(this.get_element(), "mousedown", this._mouseDownHandler);

    this._mouseDownHandler = null;

    ShoppingCartNamespace.DraggableProductBehavior.callBaseMethod(this, 'dispose');

  }

}

 

Here, we give a typical MS AJAX styled JavaScript definition for a class prototype. Since there are detailed explanations accompanying the above code, we won't cover it any further, while there's one more word to be added -- note how we have implemented each method of the IDragSource interface and tell the DragDropManager to start the dragging operation.

Finally, you have to register the DraggableProductBehavior's behavior into the MS AJAX client-side framework:

 

ShoppingCartNamespace.DraggableProductBehavior.registerClass(

  "ShoppingCartNamespace.DraggableProductBehavior",

  Sys.UI.Behavior,

  Sys.Preview.UI.IDragSource

);

 

Write a Behavior: ShoppingCartBehavior to make the shopping cart droppable

This behavior -- ShoppingCartBehavior, as we imagined beforehand, must implement the Sys.Preview.UI.IDropTarget interface. We will attach this behavior to the related HTML DOM element that represents the shopping cart and make it accept the draggable object.

Still, let's first define the constructor as well as some related fields:

 

ShoppingCartNamespace.ShoppingCartBehavior = function(element) {

  //initialize the base class

  ShoppingCartNamespace.ShoppingCartBehavior.initializeBase(this, [element]);

 

  // pet list in the cart

  this._pets = new Object();

}

 

Now we come to the prototype definition of ShoppingCartBehavior. Still for brevity, we'll omit the related explanations, but you should also note how we implement the methods of the IDropTarget interface and how the DragDropManager deals with registering/unregistering the dropped object.

 

ShoppingCartNamespace.ShoppingCartBehavior.prototype = {

  //get the target to drop ( in this case-the shopping cart)

  get_dropTargetElement: function() {

    return this.get_element();

  },

  //Judge whether the draggable element can be dropped onto the target

  canDrop: function(dragMode, dataType, data) {

    return (dataType == "Pet" && data);

  },

  //Drop the draggable element onto the related target

  drop : function(dragMode, dataType, data) {

    if (dataType == "Pet" && data) {

      // since there doesn't exist this kind of article in the

      //shopping cart, set the value of field Quantity 1

      if (this._pets[data.Id] == null) {

        this._pets[data.Id] = {Pet: data, Quantity: 1};

      }

      //since there's already the article in the shopping cart

      //plus 1 to field Quantity

      else {

        this._pets[data.Id].Quantity++;

      }

      //Refresh the shopping cart UI

      this._refreshShoppingCart();

 

      //restore the old color of the shopping cart

      this.get_element().style.backgroundColor = "#fff";

    }

  },

  // call this function when the draggable element is located on the drop target

  onDragEnterTarget : function(dragMode, dataType, data) {

    if (dataType == "Pet" && data) {

      //set the color of the shopping cart to grey

      this.get_element().style.backgroundColor = "#E0E0E0";

    }

  },

  //call this function when the draggable element is away from the drop target

  onDragLeaveTarget : function(dragMode, dataType, data) {

    if (dataType == "Pet" && data) {

      // restore the old color of the shopping cart

      this.get_element().style.backgroundColor = "#fff";

    }

  },

  // call this function when the draggable element is being dragged on the drop
target

  onDragInTarget : function(dragMode, dataType, data) {

  },

 

  //refresh the shopping cart with the product

  //list in the current shopping cart

  _refreshShoppingCart: function() {

    var cartBuilder = new Sys.StringBuilder();

    for (var id in this._pets) {

      cartBuilder.append("<div>");

      cartBuilder.append(this._pets[id].Pet.Name);

      cartBuilder.append(" * ");

      cartBuilder.append(this._pets[id].Quantity);

      cartBuilder.append("</div>");

    }

 

    this.get_element().innerHTML = cartBuilder.toString();

  },

 

  //Return the object holding the required product id and quantity

  getProductsToBeOrdered: function() {

    var productsToBeOrdered = new Object();

 

    for (var id in this._products) {

      productsToBeOrdered[id] = this._pets[id].Quantity;

    }

 

    return productsToBeOrdered;

  },

 

  // initialization

  initialize: function() {

    // initialize the base class

    ShoppingCartNamespace.ShoppingCartBehavior.callBaseMethod(this,
"initialize");

 

    //register the drop target in the DragDropManager

    Sys.Preview.UI.DragDropManager.registerDropTarget(this);

  },

 

  //destruction function

  dispose: function() {

    //cancel registering the drop target in the DragDropManager

    Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);

 

    ShoppingCartNamespace.ShoppingCartBehavior.callBaseMethod(this,
"dispose");

  }

}

 

Similarly, you should register ShoppingCartBehavior's behavior into the MS AJAX client-side framework (you can see that this behavior has implemented the IDropTarget interface):

 

ShoppingCartNamespace.ShoppingCartBehavior.registerClass
("ShoppingCartNamespace.ShoppingCartBehavior",

  Sys.UI.Behavior, Sys.Preview.UI.IDropTarget);

 

Last but not the least; please remember to call the notifyScriptLoaded() method of Sys.Application at the end of the ShoppingCart.js file to notify the ASP.NET AJAX client-side framework that this script has been loaded successfully:

 

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

 

Coding the web page

In Step 1, we've only browsed the snapshot of the Default.aspx web page. Now, let's dig into its related coding.

First, we have to add the necessary references to the relevant script files --PreviewScript.js, PreviewDragDrop.js, and ShoppingCart.js, as well as the Web Service-ShoppingService written a moment ago:

<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" />

    <asp:ScriptReference Path="ShoppingCart.js" />

  </Scripts>

  <Services>

    <asp:ServiceReference Path="ShoppingService.asmx" />

  </Services>

</asp:ScriptManager>

 

Next follows the related HTML element definitions, and for a beautiful look we use some CSS styles. That's all.

Obtaining the list of the pets to sell via Web Service

In this sample, after the client side has been initialized, we will invoke the server-side Web Service asynchronously to acquire the information about all the pets on the online store, as well as add a ShoppingCartBehavior action to the shopping cart, all of which should be performed within the pageLoad function (this function is a global built-in function defined by MS AJAX, which is automatically executed after the client-side framework has been initialized successfully, within which we can perform some initializations).

 

function pageLoad(sender, args) {

  // call Web Service to get all the pets related info

  ShoppingService.GetPets(onPetsGot);

 

  // add behavior ShoppingCartBehavior to the shopping cart

  $create(

    ShoppingCartNamespace.ShoppingCartBehavior,

    {"name": "myShoppingCartBehavior"},

    null,

    null,

    $get("shoppingCart")

  );

}

Here, inside the call back function onPetsGot(), we'll, according to the pet set returned from the web service, create each element corresponding to the pets within the container dynamically. And also, we should add the  DraggableProductBehavior behavior to each element inside the container-petContainer.

 

function onPetsGot(result) {

  // first get the container to display all the pets

  var petContainer = $get("petContainer");

 

  // iterate through the pet collection returned from the server

  for (var index = 0; index < result.length; ++ index) {

    // current pet

    var thisPet = result[index];

 

    //Create a new DOM element-div according to current pet info, and add it to the pet container

    var petElem = document.createElement("div");

    petElem.innerHTML = thisPet.Name + " "+thisPet.Category+ " " +thisPet.Color+ " "+" - $: "

       + thisPet.Price;

    petContainer.appendChild(petElem);

 

    //add behavior DraggableProductBehavior to this product (this pet info)

    $create(

      ShoppingCartNamespace.DraggableProductBehavior,

      {"pet": thisPet}, // Set property 'pet'

      null,

      null,

      petElem

    );

  }

}

 

Dealing with the order via Web Service

When the customer finally clicks the Order button near the shopping cart, he can see a message showing the data result he cares about within a red rectangle below the shopping cart area. This is accomplished by asynchronously posting back the current information about the pets to buy that needs to be processed to the server side. The following code corresponds to the click event handler of the Order button:

 

function btnOrder_onclick() {

  //get behavior ShoppingCartBehavior attached to the shopping cart

  var shoppingCartBehavior = Sys.UI.Behavior.getBehaviorByName(

    $get("shoppingCart"),

    "myShoppingCartBehavior"

  );

 

  //Get the Id and quantity of each pet in the shopping cart

  var productsToBeOrdered =

    shoppingCartBehavior.getProductsToBeOrdered();

 

  //Call Web Service to deal with the order

  ShoppingService.Order(productsToBeOrdered, onOrdered);

}

 

As is seen from above, we first use the Sys.UI.Behavior.getBehaviorByName() method to get the behavior-ShoppingCartBehavior that is attached to the shopping cart, then obtain the Id and quantity of each pet in the shopping cart, and finally post this information back to the Web Service to be processed.

Here, still for demonstration purposes, in the call back function productsToBeOrdered() we've used an HTML element div to display the response from the server to the user:

 

function onOrdered(result) {

  OutputMsg.innerHTML=result;}

 

So much for this sample; you can press F5 and give it a test! I bet you will be attracted by the friendly interface.

Final Thoughts

In this article, we first briefly compared most of the drag and drop solutions supplied by the MS AJAX framework, then summed up the inner workings of the drag and drop mechanism on the client side. After that, we focused on the client-side interfaces IDragSouce and IDropTarget, and also the DragDropManager and gave an integrated and complex example. Finally, we should notice that the MS AJAX framework has been undergoing rapid and great changes day after day; thus, only by keeping up with the changes can we web developers create the most professional, attractive and cross-browser compatible web applications.

blog comments powered by Disqus
ASP.NET ARTICLES

- Implementing ASP.NET 4.0 Page.MetaDescriptio...
- ASP.Net Development Tips
- Intro to Sessions in ASP.Net
- Google Maps API Introduction in ASP.NET usin...
- Creating an ASP.NET 3.5 Gridview Image Galle...
- Encrypt QueryString in ASP.NET 3.5 using VB....
- ASP.NET 3.5 Drop Down List Controls
- Connect to Access Database with ASP.Net
- Secure Audio Streaming with ASP.Net and Flash
- Dynamic Sitemap and Navigation in ASP.Net
- Implement Gzip and Deflate Compression in AS...
- Run ASP.Net in Ubuntu with Apache
- ASP.Net Mono Website Contact Forms
- ASP.Net URL Rewriting Methods
- Murach`s ASP.NET 4 Web Programming with C# 2...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 8 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials