Search code examples
vb.netwinformsdrag-and-drop

Drag and drop cancel


I have a Form with 2 Panels:
Panel1.BackColor is Color.Red
Panel2.BackColor is Color.Blue

When dragging panel1 to panel2, panel2 must take the color of panel1
When starting the drag operation panel1 must change color to white
When drag and drop is completed panel1 must return to color red.

All this is accomplished, but I still miss this:
if the drag and drop operation is cancelled (used dropping on other control, hitting ESC etc.) then the color of panel2 remains white, it does not revert to Color.Red.

How do I accomplish this?

I have tried to look at QueryContinueDrag, but can't seem to find a solution.

This is the code I have:

Public Class Form1

    Private dragBoxFromMouseDown As Rectangle

    Private Sub Panel1_MouseDown(sender As Object, e As MouseEventArgs) Handles Panel1.MouseDown
        Dim dragSize As Size = SystemInformation.DragSize
        dragBoxFromMouseDown = New Rectangle(New Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize)
    End Sub

    Private Sub Panel1_MouseMove(sender As Object, e As MouseEventArgs) Handles Panel1.MouseMove
        If ((e.Button And MouseButtons.Left) = MouseButtons.Left) Then
            If (Rectangle.op_Inequality(dragBoxFromMouseDown, Rectangle.Empty) And Not dragBoxFromMouseDown.Contains(e.X, e.Y)) Then
                Panel1.BackColor = Color.White
                Panel1.DoDragDrop(sender.name, DragDropEffects.All)

            End If
        End If
    End Sub

    Private Sub Panel2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Panel2.DragEnter
        If e.Data.GetData(DataFormats.Text).contains("Panel1") Then
            e.Effect = DragDropEffects.Copy
        End If
    End Sub

    Private Sub Panel2_DragDrop(sender As Object, e As DragEventArgs) Handles Panel2.DragDrop
        Panel2.BackColor = Me.Controls(e.Data.GetData(DataFormats.Text)).backcolor
        Me.Controls(e.Data.GetData(DataFormats.Text)).backcolor = Color.Red
    End Sub
End Class

Solution

  • As you have mentioned, you should handle the QueryContinueDrag event of the source Panel, to determine what action is being performed. It could be Continue, Drop or Cancel.
    You want to restore the background color of the source Control when the current action is DragAction.Drop or DragAction.Cancel.

    I've refactored some of the code presented here, because it contains some weird stuff.
    For example, you can simply pass the Control instance to the DoDragDrop() method, then verify with e.Data.GetDataPresent() that it contains the Type you want to handle.
    Also, some null checks are missing

    Private panelQueryDragPosition As Point
    Private Sub Panel1_MouseDown(sender As Object, e As MouseEventArgs) Handles Panel1.MouseDown
        panelQueryDragPosition = e.Location
    End Sub
    
    Private Sub Panel1_MouseMove(sender As Object, e As MouseEventArgs) Handles Panel1.MouseMove
        If e.Button = MouseButtons.Left AndAlso
            (Math.Abs(e.X - panelQueryDragPosition.X) > SystemInformation.DragSize.Width OrElse
             Math.Abs(e.Y - panelQueryDragPosition.Y) > SystemInformation.DragSize.Height) Then
            Dim ctl = DirectCast(sender, Panel)  ' The source Control cannot be null here
            ctl.BackColor = Color.White
            ctl.DoDragDrop(ctl, DragDropEffects.Copy)
        End If
    End Sub
    
    Private Sub Panel1_QueryContinueDrag(sender As Object, e As QueryContinueDragEventArgs) Handles Panel1.QueryContinueDrag
        If e.Action = DragAction.Drop OrElse e.Action = DragAction.Cancel Then
            Dim ctl = DirectCast(sender, Control)
            If ctl IsNot Nothing Then ctl.BackColor = Color.Red
        End If
    End Sub
    
    Private Sub Panel2_DragEnter(sender As Object, e As DragEventArgs) Handles Panel2.DragEnter
        If e.Data IsNot Nothing AndAlso e.Data.GetDataPresent(GetType(Panel)) Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If
    End Sub
    
    Private Sub Panel2_DragDrop(sender As Object, e As DragEventArgs) Handles Panel2.DragDrop
        Dim panel = DirectCast(sender, Panel)
        If panel IsNot Nothing AndAlso e.Data IsNot Nothing AndAlso e.Data.GetDataPresent(GetType(Panel)) Then
            Dim sourceControl = DirectCast(e.Data.GetData(GetType(Panel)), Panel)
            panel.BackColor = sourceControl.BackColor
        End If
    End Sub