WPF - Usando Drag and Drop (Arrastar e Soltar)


 Neste artigo eu vou mostrar como podemos realizar operações Drag and Drop (arrastar e soltar) em uma aplicação WPF.

 

As operações de Drag and Drop (arrastar e soltar) são bastante comuns nos mais diversos tipos de aplicações e normalmente referem-se a um método de transferência de dados que envolve o uso de um mouse (ou algum outro dispositivo apontador) para selecionar um ou mais objetos, arrastando e soltando esses objetos sobre algum destino na interface de usuário(UI).

É um recurso nativo das aplicações Windows Forms fácil de implementar e utilizar em diversas aplicações.

E como seria o suporte a essas operações em aplicações WPF ?

As operações de arrastar-e-soltar normalmente envolvem duas partes: uma origem (drag) a partir da qual o objeto de origem é arrastado e um destino(drop) que recebe o objeto.

A fonte (drag) e o destino (drop) podem ser elementos de interface do usuário no mesmo aplicativo ou em um aplicativo diferente.

O tipo e o número de objetos que podem ser manipulados com drag-and-drop é completamente arbitrário. Por exemplo, arquivos, pastas e seleções de conteúdo são alguns dos objetos mais comuns manipulados através de operações de arrastar-e-soltar.

As ações específicas realizadas durante uma operação de arrastar-e-soltar são de aplicação específica, e muitas vezes são determinadas pelo contexto. Por exemplo, arrastar uma seleção de arquivos de uma pasta para outra no mesmo dispositivo de armazenamento move os arquivos por padrão, enquanto arrastar arquivos a partir de um Universal Naming Convention(UNC) compartilha com uma pasta local cópias dos arquivos.

As facilidades das operações drag and drop fornecidas pelo WPF foram projetadas para ser altamente flexíveis e personalizáveis suportando uma ampla variedade de cenários. Assim o drag-and-drop suporta manipulação de objetos dentro de um único aplicativo, ou entre diferentes aplicações, bem como entre aplicativos WPF e outros aplicativos Windows.

Na WPF, qualquer UIElement ou ContentElement pode participar de um drag-and-drop. Os eventos e os métodos necessários para operações de arrastar-e-soltar são definidas na classe DragDrop.

As classes UIElement e ContentElement contêm aliases para os eventos DragDrop vinculados, de forma que os eventos aparecem na lista de membros de classe quando um UIElement ou ContentElement for herdado como um elemento base. Os manipuladores de eventos que estão conectados a esses eventos estão ligados ao DragDrop subjacente e recebem a mesma instância de dados de evento.

Os principais eventos envolvidos em uma operação Drag and Drop são:

DragEnter Ocorre quando um elemento é arrastado para os limites do destino (drop)
DragLeave Ocorre quando um elemento é arrastado para fora dos limites do destino (drop)
DragOver Ocorre continuamente enquanto um objeto é arrastado (deslocado) dentro do limite do destino
Drop Ocorre quando um objeto é lançado(solto) sobre o destino.

Neste artigo eu vou mostrar um exemplo usando drag and drop onde teremos uma aplicação WPF contendo um controle ListBox sobre o qual o usuário poderá soltar arquivos de forma que ao completar a operação os nomes completos dos arquivos serão exibidos no ListBox.

A aplicação contém um controle Button e um controle TextBox. No controle TextBox o usuário poderá definir o local de destino para onde os arquivos serão copiados e no evento Click do controle Button iremos realizar a cópia dos arquivos que foram arrastados para o ListBox para o local de destino definido.

Para dar suporte à operação drag and drop usando o controle ListBox na WPF temos que fazer o seguinte:

- Definir a sua propriedade AllowDrop como True
- Tratar o evento Drop de forma a ler o conteúdo arrastado via argumento DragEventArgs
 

Recursos usados :

Criando o projeto no VS 2013

Abra o VS 2013 Express for Windows desktop e clique em New Project;

A seguir selecione Visual Basic -> WPF Application;

Informe o nome Drag_Drop e clique no botão OK;

Abra o arquivo MainWindow.xaml e no modo Design vamos incluir os seguintes controles a partir da ToolBox:

Disponha os controles conforme o leiaute da figura abaixo:

O código gerado no arquivo MainWindow.xaml pode ser visto a seguir:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Drag and Drop - WPF" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="305*"/>
            <ColumnDefinition Width="212*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Relação de arquivos" FontSize="20" Grid.Row="0" Grid.ColumnSpan="2">
        </TextBlock>
        <ListBox Name="lb_RelacaoArquivos" Grid.Row="1" AllowDrop="True" Drop="RelacaoArquivos_Drop" Grid.ColumnSpan="2"/>
        <Button Name="btnCopiarArquivos" Grid.Row="2" Content="Copiar Arquivos" Click="btnCopiarArquivos_Click" Margin="0,0,69,0"/>
        <TextBox x:Name="txtDestino" HorizontalAlignment="Left" Height="23" Margin="14,5,0,0" Grid.Row="2" TextWrapping="Wrap" Text="C:\Dados\" VerticalAlignment="Top" Width="188" Grid.Column="1"/>
        <Label x:Name="lblDestino" Content="Destino :" HorizontalAlignment="Left" Margin="241,5,0,0" Grid.Row="2" VerticalAlignment="Top"/>
    </Grid>
</Window>

Agora vamos tratar o evento Drop do controle ListBox - lb_RelacaoArquivos definindo o código abaixo neste evento no arquivo MainWindow.xaml.vb :

Nota: estou usando o namespace System.IO para acessar as classes que realizam a cópia dos arquivos

  Private Sub RelacaoArquivos_Drop(sender As Object, e As DragEventArgs)

        Try
            Dim arquivos As String() = DirectCast(e.Data.GetData(DataFormats.FileDrop, False), String())
            For Each fileName As String In arquivos
                lb_RelacaoArquivos.Items.Add(fileName)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "Erro", MessageBoxButton.OK, MessageBoxImage.Error)
        End Try
    End Sub

O código acima obtém o nome e o caminho completo dos arquivos que são arrastados sobre o ListBox.

Agora no evento Click do controle Button vamos definir o código que copia esses arquivos para o diretório de destino definido no controle TextBox - txtDestino :

 Private Sub btnCopiarArquivos_Click(sender As Object, e As RoutedEventArgs)
        If Directory.Exists(txtDestino.Text) Then
            Try
                For Each item In lb_RelacaoArquivos.Items
                    Dim arquivo As String = Path.Combine(txtDestino.Text, New FileInfo(item.ToString()).Name)
                    If Not File.Exists(arquivo) Then
                        File.Copy(item.ToString(), arquivo)
                    End If
                Next
                MessageBox.Show("Arquivos copiados com sucesso ", "Arquivos Copiados", MessageBoxButton.OK, MessageBoxImage.Information)
            Catch ex As Exception
                MessageBox.Show("Erro : " + ex.Message, "Erro", MessageBoxButton.OK, MessageBoxImage.Error)
            End Try
        Else
            MessageBox.Show("O diretório de destino não existe.", "Erro", MessageBoxButton.OK, MessageBoxImage.Error)
        End If
    End Sub

No código acima verificamos se o diretório de destino existe e percorremos o controle ListBox obtendo os nomes dos arquivos e copiando-os para a pasta de destino.

Executando o projeto e realizando algumas operações drag and drop teremos :

Para poder obter o conteúdo de um diretório que for arrastado e solto sobre o controle ListBox podemos usar o código abaixo no evento Drop:

 Private Sub RelacaoArquivos_Drop(sender As Object, e As DragEventArgs)
        Try
            Dim CaminhoArquivos As New List(Of String)()

            For Each s In DirectCast(e.Data.GetData(DataFormats.FileDrop, False), String())
                If Directory.Exists(s) Then
                    'Adiciona arquivos a partir do diretorio
                    CaminhoArquivos.AddRange(Directory.GetFiles(s))
                Else
                    'Adiciona o caminho
                    CaminhoArquivos.Add(s)
                End If
            Next
            For Each nomeArquivo As String In CaminhoArquivos
                lb_RelacaoArquivos.Items.Add(nomeArquivo)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "Erro", MessageBoxButton.OK, MessageBoxImage.Error)
        End Try
End Sub

Este código irá obter os nomes de todos os arquivos contidos na raiz do diretório arrastado.

Se o diretório contiver outras pastas com arquivos, para obter os respectivos arquivos teremos que usar recursividade e isso não foi implementado neste código.

No exemplo abaixo vemos os arquivos da pasta ASP.NET 4.5 Features_arquivos sendo exibidos no ListBox após a mesma ser arrastada para o controle :

E como fazemos para arrastar e soltar uma imagem ?

Elementar. Basta definir o código abaixo:

If e.Data.GetDataPresent("FileName") Then
     Dim fileName As String = TryCast(e.Data.GetData("FileName"), String())(0)
     Dim fInfo As New FileInfo(fileName)
     If fInfo.Extension = ".png" OrElse fInfo.Extension = ".jpg" Then
             Me.Background = New ImageBrush(New BitmapImage(New Uri(fileName)))
     End If
End If

Pegue o projeto completo aqui: Drag_Drop.zip

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti