Welcome to AspAdvice Sign in | Join | Help

Alessandro Gallo

.NET & Beyond
Drag and Drop with Atlas: interfaces

In a previous post I gave a quick introduction to the Atlas Drag&Drop system. The core of this system is the Sys.UI.DragDropManager instance; this global-scoped object provides a cross-browser engine to handle drag&drop operations. As I said before, to build a drag&drop enabled UI we have to deal with draggable items (or controls) and drop targets. Let's start by defining

  • a draggable item as a control that implements the Sys.UI.IDragSource interface
and
  • a drop target as a control that implements the Sys.UI.IDropTarget interface.
Basically, the DragDropManager handles a drag&drop operation by invoking the implementations of one or both these interfaces on a particular control, while from the control's point of view the DragDropManager is basically used to

 

  • start a drag operation, by invoking its startDragDrop() method, if we are implementing the IDragSource interface; this method accepts three parameters: the drag source (usually a reference to the control), the drag visual (e.g. something to display under the mouse during the drag operation) and a context object.
  • register or unregister a drop target, by invoking the registerDropTarget() or unregisterDropTarget() methods, if we are implementing the IDropTarget interface. Both these methods accept a reference to the control that is acting as the drop zone.
To make things easier to understand, I decided to code the simplest (and dummiest) implementations of the IDragSource and the IDropTarget interfaces. The results are two behaviors (DraggableControlBehavior and DropZoneBehavior) that you can attach to a generic Atlas control and start seeing how things work. For example, you could insert a debug.trace() call in each method implementation to trace the calls made by the DragDropManager.While these two behaviors are really useless from an application point of view, they could be used as skeleton implementations to build more complex controls and behaviors.
The following two paragraphs list the methods defined by the IDragSource and the IDropTarget interfaces; at the end of each paragraph you'll find the simplest implementation of the interface in the form of an Atlas behavior.

 

The IDragSource interface
The IDragSource interface is implemented by controls that are supposed to be draggable. It defines the following methods:

  • get_dataType, returns the data type (as a string) for this control. It means that this control should be dropped only onto target controls that have this data type in the list of their accepted data types.
  • get_data, returns the data relative to the control. Through this method, a control can expose specific data to be retrieved during the drag operation. The DragDropManager passes to this method the context object that receives when its startDragDrop() method is called.
  • get_dragMode, returns the drag mode for this control; the framework defines a Sys.UI.DragMode enumeration with two values: Move and Copy.
  • onDragStart, is invoked when the drag operation starts;
  • onDrag, is invoked while the control is being dragged;
  • onDragEnd, is invoked when the drag operation ends, i.e. when the left mouse button is released. The DragDropManager passes to this method a boolean value ("canceled") indicating if the drag operation has to be considered "valid" or not. For example, a control dropped onto a target that doesn't accept that data type causes the cancelled parameter to be set to true. Same thing happens if a control is dropped onto an area not registered with the DragDropManager as a drop target.

 

DraggableControlBehavior.js
This behaviors adds a basic drag functionality to a control. Notice how the startDragDrop() method of the DragDropManager is called in a handler for the mousedown event.

Type.registerNamespace('AtlasNotes.UI');

AtlasNotes.UI.DraggableControlBehavior = function() {
    AtlasNotes.UI.DraggableControlBehavior.initializeBase(this);
    
    var _mousedownHandler;
    
    this.initialize = function() {
        AtlasNotes.UI.DraggableControlBehavior.callBaseMethod(this, 'initialize');
        
        _mousedownHandler = Function.createDelegate(this, mousedownHandler);
        this.control.element.attachEvent('onmousedown', _mousedownHandler);
    }
    this.dispose = function() {
        this.control.element.detachEvent('onmousedown', _mousedownHandler);
        _mousedownHandler = null;

        AtlasNotes.UI.DraggableControlBehavior.callBaseMethod(this, 'dispose');
    }
    
    this.getDescriptor = function() {
        var td = AtlasNotes.UI.DraggableControlBehavior.callBaseMethod(this, 'getDescriptor');
               
        return td;
    }
    
    this.startDragDrop = function(dragVisual) {
        Sys.UI.DragDropManager.startDragDrop(this, dragVisual, null);
    }
    
    function mousedownHandler() {
        window.event.returnValue = false;
        
        this.startDragDrop(this.control.element);
    }
        
    // IDragSource Members.
    this.get_dataType = function() {        
        return 'HTML';
    }
    this.get_data = function() {
        return this.control.element;
    }
    this.get_dragMode = function() {       
        return Sys.UI.DragMode.Move;
    }
    this.onDragStart = function() {

    }
    this.onDrag = function() {

    }
    this.onDragEnd = function(cancelled) {
        debug.trace(cancelled);
    }
}
AtlasNotes.UI.DraggableControlBehavior.registerClass('AtlasNotes.UI.DraggableControlBehavior', Sys.UI.Behavior);
Sys.TypeDescriptor.addType('script', 'draggableControl', AtlasNotes.UI.DraggableControlBehavior);

The IDropTarget interface
The IDropTarget interface is implemented by controls who want to act as drop targets. It defines the following methods:

  • get_dropTargetElement, returns the element which acts as the drop target; often this method returns a reference to the associated DOM element.
  • canDrop, returns true if the current dragged control can be dropped on the target control. The test is done on two parameters passed as arguments to the method: the first is the current drag mode, the second is the data type;
  • drop, is invoked when a control is dropped on the target control. When this happens, get_dragMode(), get_dataType() and get_data() are invoked on the dragged control to get the corresponding values that are passed as parameters to this method.
  • onDragEnterTarget, is invoked when a dragged control enters the area covered by the drop target;
  • onDragLeaveTarget, is invoked when a dragged control leaves the drop target;
  • onDragInTarget, is invoked when the dragged control is over the drop target.
The last three methods receive three parameters from the DragDropManager: the current drag mode, the data type and the data exposed by the control being dragged.

 

DropZoneBehavior.js
Attaching this behavior to a control will transform it into a drop zone; when something is dropped, it raises a dropped event.

Type.registerNamespace('AtlasNotes.UI');

AtlasNotes.UI.DropZoneBehavior = function() {
    AtlasNotes.UI.DropZoneBehavior.initializeBase(this);
    
    this.dropped = this.createEvent();
    
    this.initialize = function() {
        AtlasNotes.UI.DropZoneBehavior.callBaseMethod(this, 'initialize');
        
        // Register ourselves as a drop target.
        Sys.UI.DragDropManager.registerDropTarget(this);        
    }
    this.dispose = function() {
        
        AtlasNotes.UI.DropZoneBehavior.callBaseMethod(this, 'dispose');
    }
    
    this.getDescriptor = function() {
        var td = AtlasNotes.UI.DropZoneBehavior.callBaseMethod(this, 'getDescriptor');
        
        td.addEvent('dropped', true);
        
        return td;
    }
    
    // IDropTarget members.
    this.get_dropTargetElement = function() {
        return this.control.element;
    }
    this.drop = function(dragMode, type, data) {
        // Raise a drop event.       
        this.dropped.invoke(this, Sys.EventArgs.Empty);
    }
    this.canDrop = function(dragMode, dataType) {
        return dataType == 'HTML';
    }
    this.onDragEnterTarget = function(dragMode, type, data) {

    }
    this.onDragLeaveTarget = function(dragMode, type, data) {

    }
    this.onDragInTarget = function(dragMode, type, data) {

    }
}
AtlasNotes.UI.DropZoneBehavior.registerClass('AtlasNotes.UI.DropZoneBehavior', Sys.UI.Behavior);
Sys.TypeDescriptor.addType('script', 'dropZone', AtlasNotes.UI.DropZoneBehavior);

To start experimenting with the two behaviors, just upgrade some DOM elements to Atlas controls and then add the appropriate behavior. For example:

<control id="atlasControl1">
    <behaviors>
        <dropZone />
    </behaviors>
</control>

<control id="atlasControl2">
    <behaviors>
        <draggableControl />
    </behaviors>
</control>

Sponsor
Posted: Wednesday, March 29, 2006 1:22 PM by Garbin

Comments

Recon_609 said:

You continue to help me with your posts Garbin - your samples always shed light on the unknown aspects of Atlas.

Thanks again for a great write up!!!

Steve
# April 4, 2006 7:49 PM

Danny said:

Hi Garbin,
I hope you can help me. Currently, I've implemented atlas CollapsiblePanelExtender in the drag & drop environment. It all goes well except, when I drag and drop an expanded panel to another control, I am unable to make the target inactive, leaving a blank even the panel collapses.
Please help.
Thanks
Danny
# May 15, 2006 4:42 AM

Lewis said:

something can't find anywhere is how to implement Interfaces and Behaviors through javascript rather than Atlas script.

I really like the class structure set out by Atlas but want to be able to code it all client side in javascript?

particulary the drag-drop stuff would be great.

any help?

Rgds, Lewis
# May 24, 2006 6:32 AM

Steve said:

Garbin,

Have you tried this : http://www.nikhilk.net/ScriptSharpIntro.aspx

If so, do you think it's possible to code your above sample in Script# ?
# May 25, 2006 7:57 PM

NET Development Blog said:

It's difficult to find good documentation on the Atlas drag and drop capabilities.&amp;nbsp; Luckily a member...
# May 26, 2006 7:53 AM

Garbin said:

Danny, Lewis: the Atlas forum at http://forums.asp.net/1007/ShowForum.aspx
is the best place where to post these questions, since you can open a dedicated thread and there are many people who could help you.

Steve: I read Nikhil's entry about Script# and I find it interesting, but I really like some coding patterns that dynamic languages like Javascript can provide and I feel less comfortable to use that kind of abstraction layer to program against a dynamic language.
# June 2, 2006 7:10 PM

tango said:

Hi mate
You have mentionned that for the this.drop method of the DropZoneBehavior: the get_data() are invoked on the dragged control to get the corresponding values.
I was wondering if you know how to retrieve the actual value of the dragged control?

I have been searching for a long time but i don't know how.

Thank you. Good post by the way, very useful.
# August 3, 2006 10:49 AM

Garbin said:

tango: usually the get_data() function returns a reference to the associated element, i.e. this.element if you are implementing the interface in an Atlas control, or this.control.element if you are implementing the interface in a behavior.
If myElement stores a reference to the DOM element, then myElement.control returns a reference to the associated Atlas control.
# August 3, 2006 6:51 PM

Aver said:

I was just wondering if you could provide any insight on how to create an Atlas Control Extender that encompasses the drag and drop features. I am confused on how to set the XML script variables inside of the control.. What i mean is how do i implement the following xml:

<control id="atlasControl2">

   <behaviors>

       <draggableControl />

   </behaviors>

</control>

inside of the control ?

# September 6, 2006 2:24 PM

Garbin said:

@Aver: if you need an extender, you can use the same behavior and follow the tutorial on the control toolkit sample website at http://atlas.asp.net/atlastoolkit/Walkthrough/CreatingNewExtender.aspx

If you need an Atlas control, you should copy in the control the content of the initialize and dispose methods, plus all the members of the IDragSource or IDropTarget interfaces.

If you want to submit a sample of need further help, you can use the contact form of this blog and we can continue via e-mail.

# September 8, 2006 1:56 PM

Robbye Rob said:

I appreciate your example above and I hope to understand it in the near future for one of my needs.

I did want to make a note of something that I came across while trying to get this answer.

I put two ReorderLists on the same update panel and was able to drag and drop controls from one reorderlist to another.  

There was a terrible exception error that appeared - but I know it was due to the arrays and how the array for the list was being updated.  

I messed with the code a bit to handle the error more elegantly and was able to drag and drop from one ReorderList to another.

# September 12, 2006 5:27 PM

tranzy said:

Hi

Iam trying to make the cells of a datagrid to be draggable. I have a aspx page in which I have declared a datagrid. I have 3 template columns which have an item template each. I have declared a div with a handle in it.Inside the div i have declared a databinder.When i run app, only the first row is draggable and not the others. Could you please help me out whether i have missed something out.

C#:  

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!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>Untitled Page</title>

</head>

<body>

   <form id="form1" runat="server">

   <atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true">

    <Scripts>

          <atlas:ScriptReference ScriptName="AtlasUIDragDrop" />

          <atlas:ScriptReference Path="DropZoneBehavior.js" />

          <atlas:ScriptReference Path="DraggableControlBehavior.js" />

    </Scripts>

   </atlas:ScriptManager>

      <div class="main">

           <!-- Left Area -->

           <div id="leftArea1" class="list1">

               <div id="content1" class="item">

                   <div id="content1Handle" class="itemHandle">Content 1</div>

                   <div class="itemContent">

                       <asp:Login ID="myLogin" runat="server"

                                  CssClass="centered"></asp:Login>

                   </div>

               </div>

               <div id="content2" class="item">

                   <div id="content2Handle" class="itemHandle">Content 2</div>

                   <div class="itemContent">

                       <asp:TextBox ID="myTextBox" runat="server"></asp:TextBox>

                       <asp:Button ID="myButton" runat="server"

                                   Text="ClickMe" />

                       <br />

                       <asp:DataGrid id ="DragGrid" runat = "server" AutoGenerateColumns="false">

                           <Columns>

                               <asp:TemplateColumn HeaderText = "ID">

                                   <ItemTemplate>

                                       <div id = "CellContent1" class = "CellClassContent1">

                                           <div id ="CellContentHandle1" class = "CellClassContentHandle1"></div>

                                       </div>

                                        <div class="CellContentHandleContent1"><%# DataBinder.Eval(Container.DataItem,"TimeZoneId")%></div>

                                   </ItemTemplate>

                               </asp:TemplateColumn>

                               <asp:TemplateColumn HeaderText = "Name">

                                   <ItemTemplate>

                                     <div id = "CellContent2" class = "CellClassContent2">

                                         <div id ="CellContentHandle2" class = "CellClassContentHandle2">

                                           <%# DataBinder.Eval(Container.DataItem,"TimeZoneName")%>

                                         </div>

                                     </div>

                                   </ItemTemplate>

                               </asp:TemplateColumn>

                               <asp:TemplateColumn HeaderText = "Description">

                                   <ItemTemplate>

                                       <div id = "CellContent3" class = "CellClassContent3">

                                           <div id ="CellContentHandle3" class = "CellClassContentHandle3"><%# DataBinder.Eval(Container.DataItem,"UtcOffset")%></div>

                                       </div>

                                       <div class="CellContentHandleContent3"><%# DataBinder.Eval(Container.DataItem,"TimeZoneId")%></div>

                                   </ItemTemplate>

                               </asp:TemplateColumn>

                           </Columns>

                       </asp:DataGrid>

                       &nbsp;&nbsp;&nbsp;

                   </div>

               </div>

           </div>

           <!-- Right Area -->

           <div id="rightArea" class="list2">

               <div id="content3" class="item">

                   <div id="content3Handle" class="itemHandle">Content 3</div>

                   <div class="itemContent">

                       <asp:Calendar ID="myCalendar" runat="server"

                                     CssClass="centered"></asp:Calendar>

                   </div>

               </div>

           </div>

           <!-- Hide template elements -->

           <div class="templates">

               <!-- DropCue Template -->

               <div id="dropCueTemplate1" class="dropCue">Drop Cue content here</div>

               <!-- Empty Template -->

               <div id="emptyTemplate1" class="emptyList">Drop content here.</div>

           </div>

        </div>

   </form>

   <script type="text/xml-script">

       <page>

           <components>

               <control id="dropCueTemplate1">

                   <behaviors>

                       <DropZoneBehavior />

                   </behaviors>

               </control>

               <control id="CellContent2">

                   <behaviors>

                      <draggableListItem handle = "CellContentHandle2"/>

                     </behaviors>

               </control>

           </components>

       </page>

   </script>

</body>

</html>

# October 10, 2006 1:39 AM

Robert said:

Where can I find examples of this using the 1.0 beta?

# October 30, 2006 4:58 PM

Garbin said:

Robert: I'll have to find some time to make the necessary changes to the code. Btw the code should be very similar... are you experiencing any issue?

# October 30, 2006 5:16 PM

Jimmy Daresta said:

Garbin can you show the javascript code that would attach the behaviors to controls rather than the Atlas Script? Also, when I use the above code it works fine, but after I release my mouse button the dragging item visually returns to its original location. However if I click on it to move again it suddenly shifts positional to the last place it was when I released. Be nice if it stayed in the target or if it really returned to its original location.

Thanks for the code and the help.

# November 2, 2006 2:36 PM

Haridas said:

Hi, I want it with Ajax extende control(look ajax.asp.net).....If any one implemented it plz post. Thx.

# January 17, 2007 2:15 AM

Mike said:

Yeah, I guess it's just me, but I'm having trouble turning this into an AJAX Extender... Damn this Atlas / AJAX changeover...

# February 19, 2007 7:32 AM

ASP.NET AJAX Toolkit Forum Posts said:

Hi, I am trying to create a drag panel which is similar to this example: http://ajax.asp.net/ajaxtoolkit/DragPanel/DragPanel.aspx

# March 26, 2007 5:49 AM

justin said:

Any One have 1.0 v?

# August 3, 2007 6:00 AM
New Comments to this post are disabled