Drag and drop en WPF (I)

Un
req
uisito relativamente común en las aplicaciones actuales es la posibilidad de
realizar un drag and drop (arrastrar y soltar) entre
elementos. Nos permite representar fácilmente dos situaciones de la vida real,
como son el desplazamiento de objetos (en el caso de arrastrar un elemento y
soltarlo en su nueva posición) y el establecimiento de una relación entre
objetos (en el caso de arrastrar un elemento y soltarlo sobre el elemento al
que queremos enlazarlo).

Trabajando
en WPF tenemos disponible un método muy útil como es UIElement.CaptureMouse. Mediante este método podemos hacer que
cualquier UIElement se haga con el control exclusivo del ratón, y
cualquier evento generado por el ratón en otro elemento será ignorado. Esto nos
permite gestionar funcionalidad como el drag and
drop
sin interferir
en otros elementos de la interfaz. Veamos un ejemplo de cómo gestionar el
desplazamiento de un elemento sobre un canvas:

Primero
escribimos un manejador para el evento de MouseLeftButtonDown del elemento que
queremos arrastrar (en este caso una elipse):

        private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Ellipse ellipse = sender as Ellipse;

 

            if (ellipse != null)

            {

                ellipse.CaptureMouse();

            }

        }

En este
manejador nos limitamos a capturar el ratón cuando el usuario hace click sobre
nuestra elipse. Posteriormente, escribimos un manejador para el evento MouseLeftButtonUp, que hará el proceso inverso, es decir, liberar el ratón:

        private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Ellipse ellipse = sender as Ellipse;

 

            if (ellipse != null)

            {

                ellipse.ReleaseMouseCapture();

            }

        }

Ahora
la única tarea que nos queda es gestionar el movimiento de la elipse cuando
movamos el ratón. Dado que tenemos capturados los eventos del ratón, únicamente
tenemos que preocuparnos de mover la elipse cuando este se mueva, para lo que
aprovechamos el evento MouseMove:

        private void Ellipse_MouseMove(object sender, MouseEventArgs e)

        {

            Ellipse ellipse = sender as Ellipse;

 

            if (ellipse != null && ellipse.IsMouseCaptured)

            {

                Canvas.SetLeft(ellipse, e.GetPosition(MovementCanvas).X);

                Canvas.SetTop(ellipse, e.GetPosition(MovementCanvas).Y);

            }

        }

Con
este código tan sencillo hemos conseguido desplazar una elipse mediante una
operación de drag and drop.
Pese a que faltan multitud de comprobaciones para que el código sea optimo (la
elipse puede salirse de los bordes del canvas,
por ejemplo), sí que nos sirve para ilustrar nuestro primer ejemplo de drag
and drop.
En la segunda parte de este artículo, veremos cómo realizar un drag
and drop
que establezca una relación entre dos objetos.

Descarga el código completo