none
Select and drag a datagridview row with a single click RRS feed

  • Question

  • Hi

    I have a DataGridView, with a context menu, that also is the source for a number of drapdrop operations.  I am using the "FullRowSelect" mode.

    At the moment, to get the context menu to operate on the right row, the left button must be pressed, to highlight the row, and then the context menu will act on the correct row.  In a simmilar way, with DragDrop, the mouse button must be pressed again to select the row before it can be dragged.  It is important that the row is selected, because in both cases I use values from the SelectedRows collection to process the data.

    What I need is a way where the row can be clicked and dragged with a single click.

    Is this possible?

    Thanks
    Guy Joseph - Intel Quad Q9450, 4Gb Ram, 1Tb Hard Drive, NVidia 8800GT, Marian Marc 8, VB Express 2008
    Wednesday, June 17, 2009 11:00 PM

Answers

  • Hope the following sample helps.

     

    Drag and dropping to reorder rows is not built into the DataGridView, but following standard drag and drop code you can easily add this functionality to the DataGridView. The code fragment below shows how you can accomplish this. It assumes that you have a DataGridView control on your form named dataGridView1 and that the grid’s AllowDrop property is true and the necessary events are hooked up to the correct event handlers.

     

    private Rectangle dragBoxFromMouseDown;

    private int rowIndexFromMouseDown;

    private int rowIndexOfItemUnderMouseToDrop;

    private void dataGridView1_MouseMove(object sender, MouseEventArgs e)

    {

        if ((e.Button & MouseButtons.Left) == MouseButtons.Left)

        {

            // If the mouse moves outside the rectangle, start the drag.

            if (dragBoxFromMouseDown != Rectangle.Empty &&

                !dragBoxFromMouseDown.Contains(e.X, e.Y))

            {

     

                // Proceed with the drag and drop, passing in the list item.                   

                DragDropEffects dropEffect = dataGridView1.DoDragDrop(
                         dataGridView1.Rows[rowIndexFromMouseDown],
                         DragDropEffects.Move);

            }

        }

    }

     

    private void dataGridView1_MouseDown(object sender, MouseEventArgs e)

    {

        // Get the index of the item the mouse is below.

        rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;

     

        if (rowIndexFromMouseDown != -1)

        {

            // Remember the point where the mouse down occurred.
            // The DragSize indicates the size that the mouse can move
            // before a drag event should be started.               

            Size dragSize = SystemInformation.DragSize;

     

            // Create a rectangle using the DragSize, with the mouse position being

            // at the center of the rectangle.

            dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),

                                                           e.Y - (dragSize.Height / 2)),
                                                    dragSize);

        }

        else

            // Reset the rectangle if the mouse is not over an item in the ListBox.

            dragBoxFromMouseDown = Rectangle.Empty;

    }

     

    private void dataGridView1_DragOver(object sender, DragEventArgs e)

    {

        e.Effect = DragDropEffects.Move;

    }

     

    private void dataGridView1_DragDrop(object sender, DragEventArgs e)

    {

        // The mouse locations are relative to the screen, so they must be

        // converted to client coordinates.

        Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));

     

        // Get the row index of the item the mouse is below.

        rowIndexOfItemUnderMouseToDrop =

            dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;

     

        // If the drag operation was a move then remove and insert the row.

        if (e.Effect== DragDropEffects.Move)

        {

            DataGridViewRow rowToMove = e.Data.GetData(
                         typeof(DataGridViewRow)) as DataGridViewRow;

            dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);

            dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);

     

        }

    }

    • Marked as answer by GuyJos Thursday, June 18, 2009 7:43 AM
    Thursday, June 18, 2009 4:37 AM
  • Thanks for all your effort, but I discovered what I needed was much simpler:

    My MouseDown Handler for the DataGridView now reads:

        Private Sub BeginDrag(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DGVFavourites.MouseDown
            Dim data As DataGridView = CType(sender, DataGridView)
    
            ' Get the index of the item the mouse is below.
    
            Dim rowIndexFromMouseDown = DGVFavourites.HitTest(e.X, e.Y).RowIndex
            DGVFavourites.Rows(rowIndexFromMouseDown).Selected = True
    
            If DGVFavourites.SelectedRows.Count = 1 Then
                TBX1Drop.Visible = True
                TBX2Drop.Visible = True
                TBX3Drop.Visible = True
                TBX4Drop.Visible = True
                data.DoDragDrop(data.SelectedRows(0), DragDropEffects.Copy)
                TBX1Drop.Visible = False
                TBX2Drop.Visible = False
                TBX3Drop.Visible = False
                TBX4Drop.Visible = False
            End If
        End Sub
    I can see the relevance of Reordering rows in a DataGrid, but it wasn't quite what I needed.

    Thanks

    Guy Joseph - Intel Quad Q9450, 4Gb Ram, 1Tb Hard Drive, NVidia 8800GT, Marian Marc 8, VB Express 2008
    • Marked as answer by GuyJos Thursday, June 18, 2009 7:43 AM
    Thursday, June 18, 2009 7:43 AM

All replies

  • Hope the following sample helps.

     

    Drag and dropping to reorder rows is not built into the DataGridView, but following standard drag and drop code you can easily add this functionality to the DataGridView. The code fragment below shows how you can accomplish this. It assumes that you have a DataGridView control on your form named dataGridView1 and that the grid’s AllowDrop property is true and the necessary events are hooked up to the correct event handlers.

     

    private Rectangle dragBoxFromMouseDown;

    private int rowIndexFromMouseDown;

    private int rowIndexOfItemUnderMouseToDrop;

    private void dataGridView1_MouseMove(object sender, MouseEventArgs e)

    {

        if ((e.Button & MouseButtons.Left) == MouseButtons.Left)

        {

            // If the mouse moves outside the rectangle, start the drag.

            if (dragBoxFromMouseDown != Rectangle.Empty &&

                !dragBoxFromMouseDown.Contains(e.X, e.Y))

            {

     

                // Proceed with the drag and drop, passing in the list item.                   

                DragDropEffects dropEffect = dataGridView1.DoDragDrop(
                         dataGridView1.Rows[rowIndexFromMouseDown],
                         DragDropEffects.Move);

            }

        }

    }

     

    private void dataGridView1_MouseDown(object sender, MouseEventArgs e)

    {

        // Get the index of the item the mouse is below.

        rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;

     

        if (rowIndexFromMouseDown != -1)

        {

            // Remember the point where the mouse down occurred.
            // The DragSize indicates the size that the mouse can move
            // before a drag event should be started.               

            Size dragSize = SystemInformation.DragSize;

     

            // Create a rectangle using the DragSize, with the mouse position being

            // at the center of the rectangle.

            dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),

                                                           e.Y - (dragSize.Height / 2)),
                                                    dragSize);

        }

        else

            // Reset the rectangle if the mouse is not over an item in the ListBox.

            dragBoxFromMouseDown = Rectangle.Empty;

    }

     

    private void dataGridView1_DragOver(object sender, DragEventArgs e)

    {

        e.Effect = DragDropEffects.Move;

    }

     

    private void dataGridView1_DragDrop(object sender, DragEventArgs e)

    {

        // The mouse locations are relative to the screen, so they must be

        // converted to client coordinates.

        Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));

     

        // Get the row index of the item the mouse is below.

        rowIndexOfItemUnderMouseToDrop =

            dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;

     

        // If the drag operation was a move then remove and insert the row.

        if (e.Effect== DragDropEffects.Move)

        {

            DataGridViewRow rowToMove = e.Data.GetData(
                         typeof(DataGridViewRow)) as DataGridViewRow;

            dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);

            dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);

     

        }

    }

    • Marked as answer by GuyJos Thursday, June 18, 2009 7:43 AM
    Thursday, June 18, 2009 4:37 AM
  • OK, I'll give it a shot.

    I've had to convert it to VB.NET:

    Private dragBoxFromMouseDown As Rectangle
    
    Private rowIndexFromMouseDown As Integer
    
    Private rowIndexOfItemUnderMouseToDrop As Integer
    
    Private Sub dataGridView1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        
        
        If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
            
            
            ' If the mouse moves outside the rectangle, start the drag.
            
            
            If dragBoxFromMouseDown <> Rectangle.Empty AndAlso Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then
                
                
                
                
                ' Proceed with the drag and drop, passing in the list item.                   
                
                
                
                    
                Dim dropEffect As DragDropEffects = dataGridView1.DoDragDrop(dataGridView1.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
                
            End If
            
        End If
    End Sub
    
    
    
    Private Sub dataGridView1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        
        
        ' Get the index of the item the mouse is below.
        
        rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex
        
        
        
        If rowIndexFromMouseDown <> -1 Then
            
            
            ' Remember the point where the mouse down occurred.
            
            ' The DragSize indicates the size that the mouse can move
            
            ' before a drag event should be started.               
            
            Dim dragSize As Size = SystemInformation.DragSize
            
            
            
            ' Create a rectangle using the DragSize, with the mouse position being
            
            ' at the center of the rectangle.
            
            
            
                
            dragBoxFromMouseDown = New Rectangle(New Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize)
        Else
            
            
            ' Reset the rectangle if the mouse is not over an item in the ListBox.
            
            dragBoxFromMouseDown = Rectangle.Empty
            
        End If
    End Sub
    
    
    
    Private Sub dataGridView1_DragOver(ByVal sender As Object, ByVal e As DragEventArgs)
        
        
            
        e.Effect = DragDropEffects.Move
    End Sub
    
    
    
    Private Sub dataGridView1_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs)
        
        
        ' The mouse locations are relative to the screen, so they must be
        
        ' converted to client coordinates.
        
        Dim clientPoint As Point = dataGridView1.PointToClient(New Point(e.X, e.Y))
        
        
        
        ' Get the row index of the item the mouse is below.
        
        
        rowIndexOfItemUnderMouseToDrop = dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex
        
        
        
        ' If the drag operation was a move then remove and insert the row.
        
        If e.Effect = DragDropEffects.Move Then
            
            
            
            Dim rowToMove As DataGridViewRow = TryCast(e.Data.GetData(GetType(DataGridViewRow)), DataGridViewRow)
            
            dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown)
            
                
                
                
            dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove)
            
        End If
    End Sub
    


    Guy Joseph - Intel Quad Q9450, 4Gb Ram, 1Tb Hard Drive, NVidia 8800GT, Marian Marc 8, VB Express 2008
    Thursday, June 18, 2009 7:22 AM
  • Thanks for all your effort, but I discovered what I needed was much simpler:

    My MouseDown Handler for the DataGridView now reads:

        Private Sub BeginDrag(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DGVFavourites.MouseDown
            Dim data As DataGridView = CType(sender, DataGridView)
    
            ' Get the index of the item the mouse is below.
    
            Dim rowIndexFromMouseDown = DGVFavourites.HitTest(e.X, e.Y).RowIndex
            DGVFavourites.Rows(rowIndexFromMouseDown).Selected = True
    
            If DGVFavourites.SelectedRows.Count = 1 Then
                TBX1Drop.Visible = True
                TBX2Drop.Visible = True
                TBX3Drop.Visible = True
                TBX4Drop.Visible = True
                data.DoDragDrop(data.SelectedRows(0), DragDropEffects.Copy)
                TBX1Drop.Visible = False
                TBX2Drop.Visible = False
                TBX3Drop.Visible = False
                TBX4Drop.Visible = False
            End If
        End Sub
    I can see the relevance of Reordering rows in a DataGrid, but it wasn't quite what I needed.

    Thanks

    Guy Joseph - Intel Quad Q9450, 4Gb Ram, 1Tb Hard Drive, NVidia 8800GT, Marian Marc 8, VB Express 2008
    • Marked as answer by GuyJos Thursday, June 18, 2009 7:43 AM
    Thursday, June 18, 2009 7:43 AM
  • Hai I am Jegadesh.
                   I am Working as a programmer. here you displayed a partial of coding. 

                        DataGridViewRow rowToMove = e.Data.GetData(
                        typeof(DataGridViewRow)) as DataGridViewRow;

                                    dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);

                                    dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
              
                          ............???????

                   The Record is removed from datagridview while i dragged . pls make an aid to me.
                                      Waiting.

    Thanks in advancce.

    Jegadesh S.

    Monday, August 17, 2009 6:43 AM
  • I found that using the CellMouseDown event rather than the MouseDown event yielded better (more consistent) results. Handling the MouseDown event provided pretty spotty functionality - drag-and-drop was very difficult to invoke; it worked some of the time. Using the CellMouseDown made the drag-and-drop work every time.

    The code is similar for the event handlers, but the advantage of the CellMouseDown event is that you automatically get the row index in the Event Args - no need to perform a hit test.

    Also, when handling the actual DragDrop event, if you've got an underlying DataTable as the DataSource for the DataGridView, you'll need to write your code to remove and re-insert the row in the underlying DataTable rather than directly modifying the rows in the DataGridView. If you're DataGridView is databound and you attempt to manipulate the DataGridView rows directly, you'll throw an exception if/when the drag-and-drop operation succeeds.

    Note: You can cast the DataSource for the DataGridView explicitly. For example:

    DataTable dt = (DataTable)DataGridView1.DataSource;

    Thursday, September 26, 2013 9:49 PM
  • Hi, but this example has a bug.

    Let's say if you have 3 rows. Then you are dragging 1st row to 3rd.

    First row is removed with "dataGridView1.Rows.RemoveAt"

    Then the indexing changes, because you have now only 2 rows in DataGridView, the 3rd is removed (null).

    So dragging row 1 to 3 will produce invalid operation exception.

    To fix that you need to compare index of taken row and index and corrected function will be like this:

    private void dataGridView1_DragDrop(object sender, DragEventArgs e)
    
    {
    
        // The mouse locations are relative to the screen, so they must be
    
        // converted to client coordinates.
    
        Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));
    
     
    
        // Get the row index of the item the mouse is below.
    
        rowIndexOfItemUnderMouseToDrop =
    
            dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
    
     
    
        // If the drag operation was a move then remove and insert the row.
    
        if (e.Effect== DragDropEffects.Move)
    
        {
    
            DataGridViewRow rowToMove = e.Data.GetData(
                         typeof(DataGridViewRow)) as DataGridViewRow;
                    if (rowToMove.Index < 0)
                    {
                        return;
                    }
                    if (rowIndexFromMouseDown < rowIndexOfItemUnderMouseToDrop)
                    {
                        dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
                        dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop - 1, rowToMove);
                    }
                    else if (rowIndexFromMouseDown > rowIndexOfItemUnderMouseToDrop)
                    {
                        dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
                        dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
                    }
    
     
    
        }
    
    }

    Monday, October 19, 2015 10:40 PM