Arrastrar y colocar

Arrastrar y colocar es una manera intuitiva de transferir datos dentro de una aplicación o entre aplicaciones en el escritorio de Windows. La función de arrastrar y colocar permite al usuario transferir datos entre aplicaciones o dentro de una misma aplicación mediante un gesto estándar (mantener pulsado y desplazarse con el dedo o pulsar y desplazarse con el ratón o un lápiz).

API importantes: propiedad CanDrag, propiedad AllowDrop

El origen del arrastre, que es la aplicación o el área donde se desencadena el gesto de arrastrar, proporciona los datos que se van a transferir rellenando un objeto de paquete de datos que puede contener formatos de datos estándar, incluidos texto, RTF, HTML, mapas de bits, elementos de almacenamiento o formatos de datos personalizados. El origen también indica el tipo de operaciones que admite: copiar, mover o vincular. Cuando se suelta el puntero, se produce la colocación. El destino de colocación, que es la aplicación o el área debajo del puntero, procesa el paquete de datos y devuelve el tipo de operación que ha realizado.

Durante la operación de arrastrar y colocar, la interfaz de usuario de arrastre proporciona una indicación visual del tipo de operación de arrastrar y colocar que tiene lugar. Inicialmente, el origen es el que proporciona estos comentarios visuales, pero los destinos pueden cambiarlos a medida que el puntero se mueve sobre ellos.

Arrastrar y colocar permite la transferencia de datos entre o dentro de cualquier tipo de aplicación, incluidas las aplicaciones clásicas Windows, aunque este artículo se centra en la API XAML para arrastrar y colocar modernos. Una vez implementado, arrastrar y colocar funciona con fluidez en todas las direcciones, incluyendo de aplicación a aplicación, de aplicación a escritorio, y de escritorio a aplicación.

Esta es una introducción sobre lo que tiene que hacer para habilitar la función de arrastrar y colocar en la aplicación:

  1. Para habilitar la función de arrastrar en un elemento, establezca su propiedad CanDrag en true.
  2. Cree el paquete de datos. El sistema controla automáticamente las imágenes y el texto, pero para otros tipos de contenido, deberá controlar los eventos DragStarting y DropCompleted y usarlos para construir su propio paquete de datos.
  3. Para habilitar la función de colocar, establezca la propiedad AllowDrop en true en todos los elementos que pueden recibir el contenido colocado.
  4. Controle el evento DragOver para que el sistema sepa qué tipo de operaciones de arrastre puede recibir el elemento.
  5. Procese el evento Drop para recibir el contenido colocado.

Habilitar la función de arrastrar

Para habilitar la función de arrastrar en un elemento, establezca su propiedad CanDrag en true. Esto hace que el elemento, y los elementos que contiene, en el caso de colecciones como ListView, se puedan arrastrar.

Sea específico sobre lo que se puede arrastrar. Los usuarios no querrán arrastrar todo en la aplicación, solo determinados elementos, como imágenes o texto.

Aquí se muestra cómo establecer CanDrag.

<Image x:Name="Image" CanDrag="True" Margin="10,292,10,0" Height="338"/>

No es necesario realizar ningún otro trabajo para permitir la función de arrastrar, a menos que quiera personalizar la interfaz de usuario (de lo cual se trata más adelante en este artículo). La función de colocar requiere algunos pasos más.

Construcción de un paquete de datos

En la mayoría de los casos, el sistema construirá un paquete de datos automáticamente. El sistema controla automáticamente:

  • Imágenes
  • Mensaje de texto

Para otro contenido, deberá controlar los eventos DragStarting y DropCompleted y usarlos para construir su propio DataPackage.

Nota:

El evento DragStarting que se describe aquí forma parte de UIElement y es el evento correcto para construir un personalizado DataPackage. Esto es diferente del evento DragStarted en los controles Thumb, que se utiliza para el arrastre propio de los controles deslizantes y no para la transferencia de datos.

Controlar el evento DragStarting

El evento DragStarting se desencadena cuando el sistema inicia una operación de arrastre en un elemento que tiene CanDrag="True". En el controlador de eventos, se usa DragStartingEventArgs para rellenar su propiedad Data (un DataPackage) con el contenido que desea transferir y establecer RequestedOperation para indicar si la operación es una copia, movimiento o vínculo.

En primer lugar, configure el elemento XAML con un controlador de eventos para DragStarting y DropCompleted:

<TextBlock x:Name="DraggableText" CanDrag="True"
           DragStarting="DraggableText_DragStarting"
           DropCompleted="DraggableText_DropCompleted"
           Text="Drag this text to another location"/>

A continuación, en el código subyacente, controle el evento DragStarting para rellenar el paquete de datos:

private void DraggableText_DragStarting(UIElement sender, DragStartingEventArgs args)
{
    // Add the text content to the data package
    args.Data.SetText(((TextBlock)sender).Text);

    // Indicate that both Copy and Move are acceptable
    args.Data.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Move;
}

Si necesita realizar un trabajo asincrónico al construir el paquete de datos (por ejemplo, leer un archivo), use el método GetDeferral para mantener el evento activo hasta que se complete el trabajo:

private async void DraggableText_DragStarting(UIElement sender, DragStartingEventArgs args)
{
    var deferral = args.GetDeferral();
    try
    {
        // Perform async work here, for example loading file content
        string content = await LoadCustomTextAsync();
        args.Data.SetText(content);
        args.Data.RequestedOperation = DataPackageOperation.Copy;
    }
    finally
    {
        deferral.Complete();
    }
}

Control del evento DropCompleted

El evento DropCompleted se desencadena en el origen de arrastre después de que finalice la operación de arrastrar y soltar, tanto si el elemento se soltó correctamente como si se canceló el arrastre. Use la propiedad DropCompletedEventArgs.DropResult para determinar el resultado y tomar medidas, como quitar el elemento de origen si se realizó un movimiento :

private void DraggableText_DropCompleted(UIElement sender, DropCompletedEventArgs args)
{
    if (args.DropResult == DataPackageOperation.Move)
    {
        // The target accepted the data as a Move, so clear the source
        ((TextBlock)sender).Text = string.Empty;
    }
}

Para obtener un ejemplo completo de arrastrar y colocar personalizado con un paquete de datos, consulte el ejemplo de arrastrar y colocar XAML en GitHub.

Habilitar la función de colocar

El marcado siguiente muestra cómo se puede usar la propiedad AllowDrop para especificar que un área de la aplicación es un destino de colocación válido para un elemento arrastrado (el área especificada no debe tener un fondo nulo, debe poder recibir la entrada del puntero y el elemento no se puede quitar en ningún lugar distinto del área especificada).

Nota:

Normalmente, un elemento de la interfaz de usuario tiene un fondo nulo de forma predeterminada. Si quieres que los usuarios puedan quitar un elemento en cualquier parte de la aplicación, el fondo de la aplicación no puede ser NULL (establecer Background="Transparent" si el fondo no debe estar visible).

<Grid AllowDrop="True" DragOver="Grid_DragOver" Drop="Grid_Drop"
      Background="LightBlue" Margin="10,10,10,353">
    <TextBlock>Drop anywhere in the blue area</TextBlock>
</Grid>

Gestionar el evento DragOver

El evento DragOver se desencadena cuando un usuario ha arrastrado un elemento sobre la aplicación, pero aún no lo ha colocado. En este controlador, tiene que especificar qué tipo de operaciones admite la aplicación mediante la propiedad AcceptedOperation. Copiar es lo más habitual.

private void Grid_DragOver(object sender, DragEventArgs e)
{
    e.AcceptedOperation = DataPackageOperation.Copy;
}

Procesamiento del evento Drop

El evento Drop se produce cuando el usuario suelta elementos en un área de colocación válida. Procéselos mediante la propiedad DataView.

Para facilitar las cosas, en el siguiente ejemplo supondremos que el usuario ha colocado una sola foto y accede a ella directamente. En realidad, los usuarios pueden colocar varios elementos de distintos formatos simultáneamente. La aplicación debe controlar esta posibilidad comprobando qué tipos de archivos se han colocado y cuántos hay, y procesando cada uno en consecuencia. También debe considerar la posibilidad de notificar al usuario si está intentando hacer algo que la aplicación no admite.

private async void Grid_Drop(object sender, DragEventArgs e)
{
    if (e.DataView.Contains(StandardDataFormats.StorageItems))
    {
        var items = await e.DataView.GetStorageItemsAsync();
        if (items.Count > 0)
        {
            var storageFile = items[0] as StorageFile;
            var bitmapImage = new BitmapImage();
            bitmapImage.SetSource(await storageFile.OpenAsync(FileAccessMode.Read));
            // Set the image on the main page to the dropped image
            Image.Source = bitmapImage;
        }
    }
}

Personalizar la interfaz de usuario

El sistema proporciona una interfaz de usuario predeterminada para arrastrar y colocar. Sin embargo, también puede elegir personalizar varias partes de la interfaz de usuario estableciendo subtítulos y glifos personalizados, u optando por no mostrar una interfaz de usuario en absoluto. Para personalizar la interfaz de usuario, use la propiedad DragEventArgs.DragUIOverride.

private void Grid_DragOverCustomized(object sender, DragEventArgs e)
{
    e.AcceptedOperation = DataPackageOperation.Copy;
    e.DragUIOverride.Caption = "Custom text here"; // Sets custom UI text
    // Sets a custom glyph
    e.DragUIOverride.SetContentFromBitmapImage(
        new BitmapImage(
            new Uri("ms-appx:///Assets/CustomImage.png", UriKind.RelativeOrAbsolute)));
    e.DragUIOverride.IsCaptionVisible = true; // Sets if the caption is visible
    e.DragUIOverride.IsContentVisible = true; // Sets if the dragged content is visible
    e.DragUIOverride.IsGlyphVisible = true; // Sets if the glyph is visibile
}

Abrir un menú contextual en un elemento que se puede arrastrar con la función táctil

Al usar la función táctil, arrastrar un UIElement y abrir su menú contextual comparte gestos táctiles similares; cada acción comienza con pulsar y sostener. Así es como el sistema anula la ambigüedad entre las dos acciones de los elementos de la aplicación que admiten ambas:

  • Si un usuario pulsa y sostiene un elemento y comienza a arrastrarlo en menos de 500 milisegundos, el elemento se arrastra y no aparece el menú contextual.
  • Si el usuario pulsa y sostiene el elemento, pero no lo arrastra en menos de 500 milisegundos, se abre el menú contextual.
  • Una vez abierto el menú contextual, si el usuario intenta arrastrar el elemento (sin levantar el dedo), se descarta el menú contextual y se inicia la acción de arrastrar.

Designación de un elemento de un control ListView o GridView como carpeta

Puede especificar un ListViewItem o GridViewItem como carpeta. Esto es especialmente útil para los escenarios TreeView y Explorador de archivos. Para ello, establezca explícitamente la propiedad AllowDrop en True en ese elemento.

El sistema mostrará automáticamente las animaciones adecuadas para colocar en una carpeta en lugar de en un elemento que no sea de carpeta. El código de la aplicación debe seguir controlando el evento Drop en el elemento de carpeta (así como en el elemento que no es de carpeta) para actualizar el origen de datos y agregar el elemento colocado a la carpeta de destino.

Habilitar la reordenación mediante arrastrar y soltar en vistas de listas

ListViews admite la reordenación basada en arrastrar de forma predeterminada, usando una API muy similar a la api CanDrop que se describe en este artículo. Como mínimo, puede agregar las propiedades AllowDrop y CanReorderItems.

Consulte ListViewBase.CanReorderItems para más información.

Implementación de una función de arrastrar y colocar personalizada

La clase UIElement realiza la mayor parte del trabajo de implementación de la función de arrastrar y colocar automáticamente. Pero si lo desea, puede implementar su propia versión mediante las siguientes API.

Funcionalidad SDK de Aplicaciones para Windows
espacio de nombres Microsoft.UI.Input.DragDrop
DragPrimitive DragOperation
Crea un paquete de datos DataPackage
Envía la acción de arrastrar al shell DragOperation.StartAsync
Recibe la acción de colocar del shell DragDropManager.TargetRequested
IDropOperationTarget

Consulte también