Desenvolvimento - C#

.NET: Drag and Drop na prática usando TableLayoutPanel

Neste artigo o autor apresenta um exemplo prático do recurso Drag and Drop. O Framework .NET possui uma estrutura para tratamento dos eventos relacionados que torna muito simples o desenvolvimento de sistemas usando o conceito de arrastar e soltar.

por Marcos Dell Antonio



Neste artigo apresento um exemplo prático do recurso Drag and Drop. O Framework .NET possui uma estrutura para tratamento dos eventos relacionados que torna muito simples o desenvolvimento de sistemas usando o conceito de arrastar e soltar.

Já foram abordados em outros artigos a aplicação deste conceito usando TextBox para arrastar e soltar um texto (seja ele entre controles internos ou entre uma aplicação externa e um controle interno). Se você precisar de material complementar, coloquei vários links nas referências.

O Problema

Precisamos desenvolver um módulo de um sistema que será responsável pelo planejamento e controle de produção (PCP) da empresa. Neste módulo, será necessária uma tela onde o usuário vai acompanhar o quanto cada máquina da empresa está produzindo e as informações pertencentes a cada uma delas. Dinamicamente, os valores para cada máquina vão sendo alterados e o usuário também poderá movimentar uma máquina de uma posição para outra (esse é o foco do artigo e aqui que entra o conceito de Drag and Drop). Veja na figura abaixo o resultado final da nossa aplicação:

A Solução

Para resolver esse problema, vamos criar uma aplicação no Visual Studio usando um controle que está presente na nova versão do Framework, o TableLayoutPanel. Ele representa basicamente uma tabela (linhas e colunas).

Através dos conceitos de Drag and Drop, vamos possibilitar ao usuário movimentar as máquinas entre as posições do TableLayoutPanel.

Neste exemplo, não vou possibilitar a criação de máquinas dinamicamente, o que seria desejável para o mundo real. Serão usadas somente duas máquinas, mas nada impede que você crie um menu e adicione algumas linhas de comando para criá-las em tempo de execução.

Interface

Crie um novo projeto (File / New Project) do tipo Windows Application com o nome DragAndDropNaPratica.

Com o projeto criado, adicione o controle TableLayoutPanel e um Button. Defina as seguintes propriedades para o form e para os controles:

Form:
- Name = frmPCP
- Text = Controle de Produção
- MaximizeBox = false
- StartPosition = CenterScreen

TableLayoutPanel:
- Name = tlpMaquinas
- CellBorderStyle = OutsetPartial
- AutoScroll = true
- Criei quatro colunas e duas linhas (conforme a figura abaixo). Você pode fazer isso através da propriedade Collumns/Rows ou da SmartTag do TableLayoutPanel. Para que fiquem da maneira correta, defina para as collumns o Size Type para Percent igual a 25% e para as rows o Size Type para Percent igual a 50%. Abaixo eu mostro uma imagem da configuração:

Columns:

Rows:

Button:

- Name = btnFechar

- Text = Fechar

Além disso, no evento Click do botão, adicionei o método Close() para fechar o form. A implementação ficou assim:

O projeto deve ter ficado como segue abaixo:

Para cada posição do nosso TableLayoutPanel vamos colocar um Panel dentro. Serão oito Panels no total. Cada um deles vai representar uma posição do nosso controle de produção. Vou usar isso, pois é mais fácil para adicionar uma máquina a um Panel do que a uma posição do TableLayoutPanel. Deve ficar como segue abaixo:

Para adicionar esses Panels, observe que com a definição da borda da TableLayoutPanel para OutsetPartial, se você arrastar um Panel da ToolBox dentro de uma posição do TableLayoutPanel, ele já vai se ajustar automaticamente.

Além de adicionar os Panels, eu alterei o nome de todos eles para pnlMaquinaLC, onde L é o número da linha e C o número da coluna em que ele se encontra. Na primeira linha, da esquerda pra direita, os nomes dos Panels são os seguintes: pnlMaquina11, pnlMaquina12, pnlMaquina13 e pnlMaquina14. Já na segunda linha, também da esquerda pra direita, os nomes são: pnlMaquina21, pnlMaquina22, pnlMaquina23 e pnlMaquina24.

O que foi feito até agora foi somente criar a estrutura necessária para que possamos adicionar nossas máquinas. Como falei anteriormente, vamos usar duas máquinas. Elas serão representadas através de Panels (um para cada uma) e posicionadas em uma das áreas do TableLayoutPanel (consequentemente, ficarão dentro de um dos oito Panels que foram criados antes).

Em outras palavras, teremos uma máquina representada por um Panel, que ficará sobre uma das posições do TableLayoutPanel que também é formada por um Panel.

Para criar as duas máquinas, arraste dois Panels em posições diferentes do TableLayoutPanel (tome cuidado para arrastar dentro de um dos oito Panels). Para cada Panel criado, já pode ser definida a propriedade Dock para Fill, assim ele ficará dentro do Panel correspondente a posição no TableLayoutPanel. Depois disso, adicione 3 Labels e 2 TextBox dentro de cada Panel novo.

Abaixo seguem as propriedades a serem definidas em cada Panel:

Panel 1 (qualquer um deles)
- Name = pnlMaquina1
- BorderStyle = FixedSingle
- Dock = Fill

Panel 2 (qualquer um deles)
- Name = pnlMaquina2
- BorderStyle = FixedSingle
- Dock = Fill

Quanto as propriedades das Labels e dos Textbox, configure do jeito que preferir. O projeto (executando) deve ficar assim:

Depois de toda a interface criada, vamos configurar os controles adicionados para aceitar a nossa implementação de Drag and Drop. Para isso, defina a propriedade AllowDrop para True de todos os Panels (8 do TableLayoutPanel e 2 das máquinas) e também do TableLayoutPanel. Lembre-se de definir as propriedades dos dois Panels que ficaram por baixo das duas máquinas

Implementação

Vou explicar rapidamente como funciona o Drag and Drop do .NET. Para maiores informações, consulte as referências do artigo.

Existe um método que é usado para realizar essa tarefa de Drag and Drop. Ele é chamado de DoDragDrop. Sempre que você clica em uma máquina para arrastá-la pelo TableLayoutPanel, esse método deverá ser chamado indicando que um Drag and Drop está acontecendo. Para definir isso, vamos implementar no evento MouseDown das duas máquinas (os dois Panels) o seguinte:

Máquina 1 (pnlMaquina1 - evento MouseDown):

Máquina 2 (pnlMaquina2 - evento MouseDown):

Com isso feito, ao clicarmos sobre uma das máquinas o framework irá chamar o método DoDragDrop que realiza o processo de Drag and Drop. Esse método recebe dois parâmetros: o valor que está sendo movido (neste caso é a máquina, pois queremos mudar ela de posição) e os efeitos possíveis do Drag and Drop (neste caso é mover, pois pretendemos mover a máquina de uma posição pra outra). O que nos falta fazer agora é verificar em qual dos componentes o usuário irá soltar o mouse para mover a máquina. Para isso, vamos usar dois eventos: DragEnter e DragDrop. O DragEnter será usado para quando o mouse entrar na posição destino da máquina. Através dele, vamos alterar o cursor do mouse para o correspondente ao efeito DragDropEffects.Move.

O DragDrop é quem definitivamente irá deslocar a máquina da posição de origem para a posição destino.

Seguindo essa lógica, todas as posições do TableLayoutPanel precisam ficar aguardando pelo Drop, em outras palavras, todas elas precisam implementar os eventos DragEnter e DragDrop. A implementação deve ser feita como demonstrado abaixo.

- Implementação do DragEnter

Crie um método private e void chamado ControlaEfeito() que receberá um parâmetro do tipo DragEventArgs. Segue abaixo sua declaração e implementação:

Para cada Panel pertencente ao TableLayoutPanel (os oito que formam a estrutura), defina o evento DragEnter da seguinte maneira:

Não esqueça de fazer o mesmo para pnlMaquina12, pnlMaquina13, pnlMaquina14 e etc.

Obs: apesar do nome pnlMaquina11 ser bem parecido com o nome de uma das máquinas (pnlMaquina1), não foi feita nenhuma alteração nas duas máquinas. Elas só devem implementar o evento MouseDown, como mostrado anteriormente.

Veja que o evento DragEnter verifica se o dado armazenado em e.Data é do tipo Panel. Se for, então define o efeito para Move, caso seja outro tipo, define para None impossibilitando o Drag and Drop.

- Implementação do DragDrop

Para cada um dos Panels do TableLayoutPanel (são oito) implemente o evento DragDrop da seguinte maneira:

Repare que a única coisa que vai mudar de um evento pra outro, é o this.pnlMaquina11. Não esqueça de fazer o mesmo para pnlMaquina12, pnlMaquina13 e etc.

Este evento é que realiza o movimento da máquina de uma posição para outra. Ele simplesmente pega o Panel destino (que é onde o click do mouse foi solto, ativando assim o DragDrop) e atribui a ele o controle presente em e.Data. Lembra que no MouseDown a gente definiu no parâmetro do DoDragDrop qual dado ia ser movido? Aí está ele, sendo copiado para o Panel destino.

Um detalhe muito importante que talvez tenha passado despercebido, é que o método Add da classe Control.ControlCollection (propriedade Controls de um Panel) remove "automaticamente" a máquina do Panel de origem. Segundo a documentação do .NET, um controle pode estar dentro de somente uma Control.ControlCollection. Por isso não foi preciso remover a máquina da sua origem, o Framework fez isso.

Qualquer dúvida quanto as implementações destes eventos, faça o download do código fonte no final do artigo.

O projeto está pronto para rodar. Como dizem nos WebCasts: "Lets Build and run". O resultado final é apresentado abaixo:

- Posição inicial das duas máquinas

- Posição alterada das duas máquinas

Observações:

- Clique sempre na área correspondente ao Panel da máquina. Se você clicar sobre o Label "Máquina 1", por exemplo, não vai conseguir movê-la;

- Sobre os cálculos dinâmicos que havia comentado no início do artigo, não implementei nenhum deles. Mas poderiam ter várias rotinas trabalhando em paralelo e executando os cálculos necessários, afinal os objetos TextBox das máquinas podem ser acessados normalmente por qualquer método.

Conclusão

O conceito de Drag and Drop não é algo novo no mercado, tanto é que já foi abordado em vários outros artigos. O que podemos criar de novo são aplicações para ele, ainda mais com os novos componentes do Framework .NET 2.0. Para o problema em questão, a solução adotada é ótima, pois permite personalizar praticamente tudo e o desenvolvimento é muito simples.

Download

Faça o download do código fonte.

Material de apoio

TableLayoutPanel Class:
http://msdn2.microsoft.com/en-us/library/system.windows.forms.tablelayoutpanel.aspx

Implementing Drag and Drop in Visual Basic .NET:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vbtchimpdragdrop.asp

Criando aplicações Drad and Drop com Windows Forms .Net:
http://www.enterpriseguys.com/Artigos.aspx?ColunistaID=23&id=55

Drag and Drop:
http://www.c-sharpcorner.com/winforms/DragAndDrop2MG.asp

Performing Drag-and-Drop Operations in Windows Forms:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbtskstartingdragoperations.asp

Marcos Dell Antonio

Marcos Dell Antonio - Profissional certificado (MCPD, MCTS e MCP) em tecnologias da Microsoft e especialista em .NET e Visual Studio Team System. Site: www.marcosdellantonio.net.