Drag-n-drop on Silverlight alpha

Published Thu, Jun 14 2007 13:55

Today I've run some tests on drag-n-drop support available for the alpha version. It ended up being really easy to add this kind of behavior to a silverlight element. Lets start by defining some elements in XAML, which are placed inside a top canvas:

<Rectangle x:Name="r" Width="66" Height="80" Canvas.Left="41" Canvas.Top="40.537"
       Fill="red" />
<Rectangle x:Name="r2" Width="66" Height="80" Canvas.Left="200" Canvas.Top="40.537"
      Fill="Green" />
<Rectangle x:Name="r3" Width="66" Height="80" Canvas.Left="300" Canvas.Top="40.537"
      Fill="Blue" />

The idea is to let the user reorganize the rectangles on the canvas by dragging them around. The user must also be able to cancel the current drag operation by pressing the ESC key (I've used the KeyUp event to handle the ESC key press).

We start by hooking up several events of the rectangles during the Load event of the top canvas element:

r.MouseLeftButtonDown += new MouseEventHandler(down);
r2.MouseLeftButtonDown += new MouseEventHandler(down);
r3.MouseLeftButtonDown += new MouseEventHandler(down);

r.MouseLeftButtonUp += new MouseEventHandler(up);
r2.MouseLeftButtonUp += new MouseEventHandler(up);
r3.MouseLeftButtonUp += new MouseEventHandler(up);

r.MouseMove += new MouseEventHandler(move);
r2.MouseMove += new MouseEventHandler(move);
r3.MouseMove += new MouseEventHandler(move);

this.KeyUp += new KeyboardEventHandler(keyUp);

As you can see, we need to handle several mouse events. We also need to handle a key press because the ESC key must cancel the current drag operation! - that is, if there's one being done.

When the user clicks over a rectangle, we need to save the rectangle's current position and Z-Index because we must return the rectangle to its initial position when the user hits the ESC key during the dragging. So, we start by adding the following fields to the Canvas class:

bool _mouseCaptured = false;
double _currentX = 0.0;
double _currentY = 0.0;
int _initialZIndex = 0;
Rectangle _current = null;

And then we can proceed to the down method, that handles the MouseLeftButtonDown:

private void down(object sender, MouseEventArgs e)
{
  _current = (Rectangle)sender;

 _currentX = (double)((Rectangle)sender).GetValue(Canvas.LeftProperty);
 _currentY = (double)((Rectangle)sender).GetValue(Canvas.TopProperty);

 ((Rectangle)sender).CaptureMouse();

 _mouseCaptured = true;

 _initialZIndex = Convert.ToInt32( ((Rectangle)sender).GetValue( Canvas.ZIndexProperty ) );
 ((Rectangle)sender).SetValue<int>(Canvas.ZIndexProperty, 10);
}

Since this method marks the beginning of a drag operation, we must initialize our auxiliary fields. Notice the CaptureMouse method call...it's really important and it's saying that all mouse events should be redirected to the current Rectangle. The z-index value is changed to a "safe" value so that the dragged rectangle remains on the top of the other elements that exist on the page (for instance, in this example, if i didn't change the z-index and i started dragging the 1st rectangle, when this rectangle was over the second rectangle, it would be placed below that second rectangle because both have were declared with the same Z-order and the second was added after the first - not what we want in this case).

A drag operation needs to handle the mouse move (only if a drag is taking place). Here's the code to do that:

void move(object sender, MouseEventArgs e)
{
   if (!_mouseCaptured) return;

  ((Rectangle)sender).SetValue<double>(Canvas.LeftProperty, e.GetPosition(this).X);
  ((Rectangle)sender).SetValue<double>(Canvas.TopProperty, e.GetPosition(this).Y);
}

When the user moves the cursor and the dragging operation has started (_mouseCaptured = true), we only need to update the Left and Top properties of the Rectangle (note how we're passing this in order to use the top canvas as the reference for the X and Y  coordinates). When the user releases the mouse button, it's time to clear the auxiliary fields and to release the mouse capture:

private void up(object sender, EventArgs e)
{
   ((Rectangle)sender).ReleaseMouseCapture();

    _mouseCaptured = false;
    ((Rectangle)sender).SetValue<int>(Canvas.ZIndexProperty, _initialZIndex);
}

The only thing that is left is cancelling a dragging operation, which is done by the keyUp method:

void keyUp(object sender, KeyboardEventArgs e)
{
  if (!_mouseCaptured || e.PlatformKeyCode != 27 ) return;
  _current.SetValue<double>(Canvas.LeftProperty, _currentX);
  _current.SetValue<double>(Canvas.TopProperty, _currentY);
  _current.SetValue<int>(Canvas.ZIndexProperty, _initialZIndex);

  _current.ReleaseMouseCapture();

  _current = null;
  _mouseCaptured = false;
}

Again, nothing too complicated...we start by checking if we're on a dragging operation and if the user hit the ESC key. If any of those conditions isn't true, we don't do anything. If they are both true, we must put the rectangle at its original place (ie, we must put it where it was before starting the dragging operation).

Filed under:

Comments

# .Net Adventures said on Thursday, June 14, 2007 3:11 PM

Drag-n-drop on Silverlight alpha 3D in Silverlight Download DinnerNow.NET Sample Application Silverlight

# Madu Alikor said on Saturday, September 29, 2007 12:52 PM

I was wondering how would you apply this drag-n-drop but instead of it object sundenly snapping to the top left hand corner of the element have it remember where within them element was clicked and keep that as the point at which the object is moved

Emm not sure if i made any sense just imagine you clicked 2/3 at the top of the rectangle how would you keep that point as the point of movement?

# Thoughts on Silverlight » BIT-101 Blog said on Tuesday, December 11, 2007 5:30 PM

Pingback from  Thoughts on Silverlight &raquo; BIT-101 Blog

# blahbal said on Friday, December 14, 2007 12:26 PM

it sucks. See how easy is to drag stuff in Flash.

# silverlight drag and drop said on Thursday, June 26, 2008 7:53 AM

Pingback from  silverlight drag and drop

# Interesting articles(June 14) | devintelligence.com said on Saturday, July 26, 2008 9:37 AM

Pingback from  Interesting articles(June 14) | devintelligence.com

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above:  

Search

This Blog

Tags

Community

Archives

Syndication

Email Notifications

News




  • View Luis Abreu's profile on LinkedIn


    Follow me at Twitter

    My books

    Silverlight 4.0: Curso Completo

    ASP.NET 4.0: Curso Completo

    Portuguese LINQ book cover

    Portuguese ASP.NET 3.5 book cover

    Portuguese ASP.NET AJAX book cover

    Portuguese ASP.NET AJAX book cover