André Alves de Lima

Talking about Software Development and more…

Implementando Drag and Drop (arrastar e soltar) em aplicações Windows Forms com C#

O tema drag and drop (arrastar e soltar) em aplicações Windows Forms é um dos assuntos mais questionados nos fóruns da MSDN. Entretanto, não consegui encontrar um artigo decente em português que mostre um passo-a-passo explicando como implementar essa funcionalidade. E foi daí que surgiu a ideia para o artigo de hoje.

Para demonstrar a funcionalidade de arrastar e soltar vamos construir dois exemplos muito simples. O primeiro exemplo mostra como arrastar itens de um ListBox para outro e o segundo exemplo mostra como arrastar um arquivo do Windows Explorer para dentro de um TextBox (de forma que o TextBox receba o caminho do arquivo arrastado).

Movendo itens de um ListBox para o outro

É muito comum que em alguma parte do nosso aplicativo tenhamos dois ListBoxes (um de destino e outro de origem) e que queiramos que itens de um ListBox sejam movidos para o outro ListBox. A maneira mais utilizada para fazer a movimentação de itens de um ListBox para o outro é através de botões. Um botão move itens no sentido “esquerda para direita” e outro botão move itens no sentido “direita para esquerda“. É possível encontrar esse tipo de implementação principalmente em Wizards dos mais diversos aplicativos da Microsoft. Por exemplo, veja o Wizard para criação de novos formulários no Microsoft Access:

Se tivermos o mesmo tipo de interface nas nossas aplicações, obviamente podemos utilizar esses tipos de botões, uma vez que todos os usuários conseguem entender exatamente como eles funcionam. Porém, que tal incrementar um pouco a usabilidade e adicionar a funcionalidade de arrastar e soltar nessas situações?

Para demonstrar como ficaria a implementação de drag and drop nesse caso, crie um projeto do tipo Windows Forms e ajuste a interface do formulário de forma que ele fique parecida com a imagem a seguir.

Antes de continuar, configure como “true” a propriedade AllowDrop em ambos os ListBoxes. Essa é a propriedade que utilizamos para indicar que o controle suportará que arrastemos “coisas” para dentro dele. Feito isso, vamos configurar o drag and drop de forma que consigamos arrastar itens de um ListBox para o outro (e vice-versa).

O processo de arrastar e soltar é dividido em três etapas. A primeira delas diz respeito ao início do processo de drag and drop. Durante a execução do aplicativo, em algum momento o controle deve dar um “sinal” para a engine do Windows Forms dizendo que uma operação de arrastar e soltar está sendo iniciada. Para emitirmos esse sinal vamos utilizar o evento MouseDown do controle ListBox. Adicione o seguinte trecho de código dentro do formulário:

        private void listBox_MouseDown(object sender, MouseEventArgs e)
        {
            ListBox listBoxOrigem = sender as ListBox;
            if (listBoxOrigem != null && listBoxOrigem.SelectedItem != null)
                DoDragDrop(sender, DragDropEffects.Move);
        }

Como você pode observar, a implementação do “sinal” para iniciar o drag and drop é muito simples. Basta verificarmos se o ListBox possui algum item selecionado no momento e, caso positivo, chamamos o método DoDragDrop. Note que o event handler acima utiliza o parâmetro “sender” para identificar o ListBox que disparou o evento MouseDown. Fazemos isso pois vamos utilizar os mesmos event handlers em ambos os ListBoxes.

A chamada do método recebe dois parâmetros. O primeiro deles representa os dados a serem movidos no processo de arrastar e soltar, e o segundo parâmetro indica as operações de drag and drop suportadas no processo que está sendo iniciado. Estamos passando o ListBox no primeiro parâmetro pois somente dessa forma conseguimos utilizar o mesmo event handler para ambos os ListBoxes. As operações de drag and drop mais utilizadas são “Copy” e “Move“. No nosso caso estamos utilizando a opção “Move“, pois estamos movendo itens de um ListBox para o outro. Confira a lista de todas as opções de arrastar e soltar disponíveis acessando a documentação do enum DragDropEffects no MSDN.

O próximo passo do processo de arrastar e soltar corresponde à autorização ou não da operação de “soltar” no controle de destino. A ideia é que temos que validar se o conteúdo pode ser “solto” ou não no controle de destino. No nosso caso, por exemplo, só permitiremos que a operação de “drop” proceda caso os dados de origem correspondam a um ListBox.

        private void listBox_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ListBox)))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }

Observe que o evento utilizado para fazer essa validação é o DragOver. Nele acessamos a propriedade “Data” do DragEventArgs e verificamos se o conteúdo é do tipo ListBox. Caso positivo, configuramos o efeito de drag and drop para “Move“. Caso negativo, configuramos o efeito de drag and drop para “None” (o que impossibilitará que o conteúdo seja “solto” dentro do ListBox).

Finalmente, a única implementação que falta é o código que fará a movimentação do item selecionado no ListBox de origem para o ListBox de destino. Esse código deve ser implementado no handler para o evento DragDrop.

        private void listBox_DragDrop(object sender, DragEventArgs e)
        {
            var listBoxOrigem = e.Data.GetData(typeof(ListBox)) as ListBox;
            var listBoxDestino = sender as ListBox;
            if (listBoxOrigem != null && listBoxDestino != null)
            {
                listBoxDestino.Items.Add(listBoxOrigem.SelectedItem);
                listBoxOrigem.Items.Remove(listBoxOrigem.SelectedItem);
            }
        }

Com a propriedade “Data” nós conseguimos acessar o ListBox que iniciou a operação de arrastar e soltar. Já com o parâmetro “sender” conseguimos acessar o ListBox de destino. Aí é só acessar o item selecionado no ListBox de origem e adicioná-lo no ListBox de destino e então finalmente remove-lo do ListBox de origem.

Por fim, associe os handlers para os eventos MouseDown, DragOver e DragDrop com os dois ListBoxes.

Execute a aplicação e você conseguirá mover itens de um ListBox para o outro justamente conforme esperado.

Esse exemplo só funciona se o ListBox estiver configurado para que somente um item possa ser selecionado por vez (propriedade SelectionMode = One). Caso queira conferir como implementar o suporte a drag and drop em ListBoxes com múltipla seleção, confira este outro artigo.

Movendo um arquivo do Windows Explorer para dentro da aplicação

O segundo exemplo trata de outro comportamento muito encontrado em aplicações nos dias de hoje. Com certeza você já teve que desenvolver um aplicativo que em algum ponto era necessário que o usuário escolhesse um arquivo. Muito provavelmente você deve ter resolvido essa necessidade utilizando a classe OpenFileDialog, que serve para mostrar um diálogo onde o usuário pode escolher um arquivo.

        private void abrirButton_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dialog = new OpenFileDialog())
            {
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    caminhoDoArquivoTextBox.Text = dialog.FileName;
                }
            }
        }

Que tal estendermos essa funcionalidade de forma que o usuário possa arrastar um arquivo do Windows Explorer para dentro do TextBox? Por sorte, isso é muito simples de ser implementado.

Primeiramente, como fizemos com os ListBoxes do exemplo anterior, temos que alterar para “true” a propriedade AllowDrop do TextBox. Feito isso, temos que implementar um handler para o evento DragOver do TextBox, onde iremos verificar qual o conteúdo que está sendo arrastado para dentro do TextBox e habilitarmos ou não a ação de “soltar” dependendo do que estiver sendo arrastado.

        private void caminhoDoArquivoTextBox_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Link;
            else
                e.Effect = DragDropEffects.None;
        }

Observe que utilizamos o método GetDataPresent da propriedade “Data” passando o tipo “DataFormats.FileDrop“. A chamada desse método retornará “true” caso um arquivo esteja sendo arrastado para dentro do TextBox. Nesse caso, alteramos o efeito do drag and drop para “Link“. Caso contrário (quando qualquer outro tipo de objeto esteja sendo arrastado para dentro do TextBox), nós cancelamos o processo de drag and drop (configurando o efeito para “None“).

Por fim, basta implementarmos um handler para o evento DragDrop do TextBox onde iremos recuperar o caminho do arquivo que foi arrastado para dentro dele.

        private void caminhoDoArquivoTextBox_DragDrop(object sender, DragEventArgs e)
        {
            string[] arquivos = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (arquivos != null && arquivos.Any())
                caminhoDoArquivoTextBox.Text = arquivos.First();
        }

Como é possível que mais de um arquivo seja selecionado para arrastar, o retorno de “GetData” será um array de strings contendo os caminhos dos arquivos que foram arrastados. No nosso exemplo, como só temos um TextBox para o caminho de um único arquivo, nós recuperamos o caminho para o primeiro arquivo que tiver sido selecionado.

Execute a aplicação, arraste um arquivo do Windows Explorer para dentro do TextBox e veja o caminho desse arquivo ser preenchido no conteúdo do TextBox.

Concluindo

A funcionalidade de drag and drop (arrastar e soltar) é implementada em muitos pontos dos aplicativos desenvolvidos pela Microsoft. Então por que será que acabamos esquecendo de implementar drag and drop nos nossos aplicativos? O real motivo eu não sei, mas, agora que você aprendeu como faz, não dá mais para usar a desculpa de que falta conhecimento.

Nesse artigo de hoje você conferiu como implementar drag and drop com ListBoxes e arquivos do Windows Explorer. Veja este outro artigo caso você queira conferir como implementar arrastar e soltar com o controle RichTextBox e este outro artigo caso queira aprender a implementar drag and drop com o controle ListView.

E você, já utiliza o conceito de arrastar e soltar na sua aplicação? Não? Então vá agora mesmo analisar os seus aplicativos e encontre os lugares onde você pode adicionar essa simples mas poderosa funcionalidade.

Para ficar por dentro de todos os novos artigos publicados no meu site toda semana, assine a minha newsletter clicando aqui ou utilizando o formulário logo abaixo. Ao assinar a minha newsletter você receberá um e-mail toda semana onde eu comento sobre o artigo que foi publicado e também explico quais são os meus planos para a próxima semana além de compartilhar dicas exclusivas que eu só compartilho por e-mail. Assine agora mesmo.

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

7 thoughts on “Implementando Drag and Drop (arrastar e soltar) em aplicações Windows Forms com C#

  • Fernando Mesquita disse:

    Olá André,
    Desde já, quero manifestar o meu apreço pelos conteúdos que aborda nos seus artigos, sendo muito úteis e oportunos.
    Aguardo com expectativa o próximo artigo sobre o reportviewer para impressão de documentos diretamente na impressora.
    Entretanto queria colocar uma questão pertinente:
    Desde há muito anos ligado à programação VB, Clipper, FoxPro (agora descontinuado) e por último VB.net.
    Acontece que nas pesquisas que faço na NET, os exemplos são apresentados, na sua maioria em C#. Assim sendo, queria saber a sua opinião sobre as vantagens de mudar para C# ou continuar em VB.net?
    Grato pela sua atenção.
    Cumprimentos,
    Fernando Mesquita

    • andrealveslima disse:

      Olá Fernando, obrigado pelo comentário!

      Realmente a maioria dos exemplos que envolvem o .NET Framework são apresentados em C#.. Porém, como o .NET Framework é comum entre o C# e VB.NET, acaba sendo que fica muito fácil converter de uma linguagem para a outra (tanto que existem inúmeros conversores automáticos na Internet)..

      A vantagem de aprender o C# é que, na minha opinião, o mercado é maior e mais especializado.. Além de você conseguir entender imediatamente a maioria dos exemplos que você encontra na Internet (ao invés de ter que ficar convertendo de C# para VB.NET)..

      Eu investiria um tempo para aprender o C# não necessariamente para substituir 100% o VB.NET, mas sim, para você ter mais uma linguagem disponível na sua “caixa de ferramentas”.. Afinal, como você já sabe programar em VB.NET (e essas outras tantas linguagens), você vai conseguir aprender C# muito rapidamente..

      É isso aí.. Espero que tenha ajudado.. Se precisar de ajuda no processo, entre em contato!

      Abraço!
      André Lima

  • Daniel disse:

    Muito bom post André. As vezes esquecemos de coisas simples que fazem muita diferença para os usuários. Obrigado e boa semana.
    Abs

  • […] Como você pode ver, é um código muito simples. Nós utilizamos a classe OpenFileDialog para selecionarmos um ou mais arquivos (note que a propriedade MultiSelect foi alterada para “true” a fim de possibilitarmos a escolha de mais de um arquivo) e, caso o usuário confirme o diálogo, nós preenchemos o ListBox com os caminhos para os arquivos escolhidos. Uma solução mais robusta seria possibilitar o drag and drop de arquivos diretamente do Windows Explorer para dentro desse ListBox. Você pode conferir como implementar essa funcionalidade no meu artigo sobre drag and drop em aplicações Windows Forms com C#. […]

  • Marcos Otilio disse:

    Olá Andre, primeiramente parabéns pelos artigos, são bastante didáticos e me ajudam demais.
    Estou com uma dúvida sobre o dragdrop, já procurei em todo lugar e não encontro, quero que quando eu tiver arrastando um objeto o mesmo seja arrastado com o mouse e não o ícone de proibido ou outro ponteiro do mouse, como é o caso de quando vou mover um ícone ou outros documentos no windows, desde já grato.

    Obs.: Aplicação WinForms – .Net Framework 4.6

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *