【问题标题】:How to drag and drop row within the same datagridview如何在同一个datagridview中拖放行
【发布时间】:2012-07-18 23:40:38
【问题描述】:

在 Windows 应用程序 (Visual Studio)(VB) 中,如何将单行拖放到另一个位置以允许用户重新排序该行?我还没有找到任何有价值的例子。

【问题讨论】:

    标签: vb.net visual-studio-2010 datagridview drag-and-drop datagridviewrow


    【解决方案1】:

    这是来自这个 C# 答案的 vb 版本:How could I Drag and Drop DataGridView Rows under each other?

    表单类变量:

    Private fromIndex As Integer
    Private dragIndex As Integer
    Private dragRect As Rectangle
    

    拖动事件:

    Private Sub DataGridView1_DragDrop(ByVal sender As Object, _
                                       ByVal e As DragEventArgs) _
                                       Handles DataGridView1.DragDrop
      Dim p As Point = DataGridView1.PointToClient(New Point(e.X, e.Y))
      dragIndex = DataGridView1.HitTest(p.X, p.Y).RowIndex
      If (e.Effect = DragDropEffects.Move) Then
        Dim dragRow As DataGridViewRow = e.Data.GetData(GetType(DataGridViewRow))
        DataGridView1.Rows.RemoveAt(fromIndex)
        DataGridView1.Rows.Insert(dragIndex, dragRow)
      End If
    End Sub
    
    Private Sub DataGridView1_DragOver(ByVal sender As Object, _
                                       ByVal e As DragEventArgs) _
                                       Handles DataGridView1.DragOver
      e.Effect = DragDropEffects.Move
    End Sub
    

    鼠标事件:

    Private Sub DataGridView1_MouseDown(ByVal sender As Object, _
                                        ByVal e As MouseEventArgs) _
                                        Handles DataGridView1.MouseDown
      fromIndex = DataGridView1.HitTest(e.X, e.Y).RowIndex
      If fromIndex > -1 Then
        Dim dragSize As Size = SystemInformation.DragSize
        dragRect = New Rectangle(New Point(e.X - (dragSize.Width / 2), _
                                           e.Y - (dragSize.Height / 2)), _
                                 dragSize)
      Else
        dragRect = Rectangle.Empty
      End If
    End Sub
    
    Private Sub DataGridView1_MouseMove(ByVal sender As Object, _
                                        ByVal e As MouseEventArgs) _
                                        Handles DataGridView1.MouseMove
      If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
        If (dragRect <> Rectangle.Empty _
        AndAlso Not dragRect.Contains(e.X, e.Y)) Then
          DataGridView1.DoDragDrop(DataGridView1.Rows(fromIndex), _
                                   DragDropEffects.Move)
        End If
      End If
    End Sub
    

    确保将 grids AllowDrop 属性设置为 true。

    【讨论】:

    • 有人能回答为什么我在 Datagridview 中拖动一行时会出现这些错误吗? Rows cannot be programmatically added to the DataGridView's rows collection when the control is data-bound.
    • @ChadPatrick 就像错误所说的那样,您的网格是数据绑定的(您有一个数据源),这意味着您不能直接操作网格。在您的情况下,您需要操作数据源。如果您有问题,请发布一个新问题并适当记录。
    • 我该如何操作数据源?这是我填充数据网格视图的代码:con = New SqlConnection con.ConnectionString = "Data Source=mssql;Initial Catalog=DATABASE;User ID=sa;Password=" con.Open() adap = New SqlDataAdapter("SELECT * FROM tablename", con) ds = New System.Data.DataSet() adap.Fill(ds, "TableNew") Datagridview1.DataSource = ds.Tables(0) con.Close()
    • @ChadPatrick 您的数据表:ds.Tables(0)。如果您在该数据表中添加一行,您的网格将自动显示它。
    【解决方案2】:

    更新:

    代替

     If dragIndex < 0 Then dragIndex = DataGridView1.RowCount - 1
    

    改成

     If dragIndex > -1 Then 
          'action if not selected in the row header and blank space
     else
          'return error if selected in the column header and blank space
     end if
    

    那么当你将一行拖到“空白区”时就会出错,不信你一定要试试。

    最终代码(仅适用于“拖动事件”部分)是这样的:

      Private Sub DataGridView1_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragDrop
            Dim p As Point = DataGridView1.PointToClient(New Point(e.X, e.Y))
            dragIndex = DataGridView1.HitTest(p.X, p.Y).RowIndex
        'Determine if dragindex is valid row index       
        If dragIndex > -1 Then
            If (e.Effect = DragDropEffects.Move) Then
                Dim dragRow As DataGridViewRow = CType(e.Data.GetData(GetType(DataGridViewRow)), DataGridViewRow)
                DataGridView1.Rows.RemoveAt(fromIndex)
                DataGridView1.Rows.Insert(dragIndex, dragRow)
                'Add this line of code if you want to put selected rows to the rows that change
                DataGridView1.Rows(dragIndex).Selected = True
            End If 
           Else 'Do any message here if selected in column header and blank space. 
           End If
        End Sub
    

    【讨论】:

      【解决方案3】:

      感谢您所做的一切,代码工作正常。我只得到一个错误。我解决了。

      如果设置了datagridview“启用编辑”,则在抛出行距时会收到错误消息。你可以试试。我解决了如下:

          Private Sub DataGridView1(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragDrop
      
          Dim p As Point = DataGridView1.PointToClient(New Point(e.X, e.Y))
                          dragIndex = DataGridView1.HitTest(p.X, p.Y).RowIndex
                          If (e.Effect = DragDropEffects.Move) Then
                              Dim dragRow As DataGridViewRow = CType(e.Data.GetData(GetType(DataGridViewRow)), DataGridViewRow)
      
                              If dragIndex = DataGridView1.RowCount - 1 Then '**ADD THIS AREA**
                                  DataGridView1.Rows.RemoveAt(fromIndex)
                                  DataGridView1.Rows.Insert(DataGridView1.RowCount - 1, dragRow)
                              Else
                                  If dragIndex < 0 Then dragIndex = DataGridView1.RowCount - 2 '**this is important**
                                  DataGridView1.Rows.RemoveAt(fromIndex)
                                  DataGridView1.Rows.Insert(dragIndex, dragRow)
                              End If
                          End If
      End Sub
      

      感谢您提供所有其他信息

      【讨论】:

        【解决方案4】:

        这是一个没有上述错误的控件。

        在 Windows 窗体设计器中将 AllowUserToOrderRowsAllowDrop 设置为 True,然后拖动行标题,而不是内容。

        Imports System.ComponentModel
        
        Public Class BetterDataGridView
            Inherits DataGridView
        
            <Category("Behavior"), DefaultValue(False)>
            Public Property AllowUserToOrderRows As Boolean = False
        
            Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
                MyBase.OnMouseDown(e)
        
                Dim hitInfo As HitTestInfo = HitTest(e.X, e.Y)
                If AllowUserToOrderRows AndAlso
                        e.Button = MouseButtons.Left AndAlso
                        hitInfo.ColumnIndex = -1 AndAlso
                        ValidRow(hitInfo.RowIndex) Then
                    DoDragDrop(Rows(hitInfo.RowIndex), DragDropEffects.Move)
                End If
            End Sub
        
            Protected Overrides Sub OnDragOver(e As DragEventArgs)
                MyBase.OnDragOver(e)
        
                Dim dragRow As DataGridViewRow = e.Data.GetData(GetType(DataGridViewRow))
                Dim targetIndex As Integer = GetRowIndex(e)
                e.Effect = If(ValidRowDragDrop(dragRow, targetIndex),
                              DragDropEffects.Move,
                              DragDropEffects.None)
            End Sub
        
            Protected Overrides Sub OnDragDrop(e As DragEventArgs)
                MyBase.OnDragDrop(e)
        
                Dim dragRow As DataGridViewRow = e.Data.GetData(GetType(DataGridViewRow))
                Dim targetIndex As Integer = GetRowIndex(e)
        
                If e.Effect = DragDropEffects.Move AndAlso ValidRowDragDrop(dragRow, targetIndex) Then
                    EndEdit()
        
                    Rows.Remove(dragRow)
                    Rows.Insert(targetIndex, dragRow)
        
                    ClearSelection()
                    dragRow.Selected = True
                End If
            End Sub
        
            Protected Function ValidRow(rowIndex As Integer) As Boolean
                Return rowIndex >= 0 AndAlso
                    rowIndex < Rows.Count - If(AllowUserToAddRows, 1, 0)
            End Function
        
            Protected Function GetRowIndex(e As DragEventArgs) As Integer
                Dim clientPos As Point = PointToClient(New Point(e.X, e.Y))
                Return HitTest(clientPos.X, clientPos.Y).RowIndex
            End Function
        
            Protected Function ValidRowDragDrop(dragRow As DataGridViewRow, targetIndex As Integer) As Boolean
                Return dragRow IsNot Nothing AndAlso
                    ValidRow(targetIndex) AndAlso
                    targetIndex <> dragRow.Index AndAlso
                    Rows.Contains(dragRow)
            End Function
        End Class
        

        【讨论】:

        • 注意:该控件只有在您成功构建项目后才会出现在工具箱中。
        • 我还发现,如果我扩展一些 WinForms 控件,那么新代码必须编译为 32 位才能工作(因此只能在工具箱中看到成功编译为32 位)。详情请见stackoverflow.com/a/26539992/1624894
        【解决方案5】:

        1.5 事件改进GridView.DragDrop

        1. 前50%的改进,为了避免描述的错误你也可以使用

          Private Sub DgvSearchFieldCurrent_DragDrop( _
             ByVal sender As  Object, ByVal e As DragEventArgs) _
             Handles DgvSearchFieldCurrent.DragDrop
          
          Dim LclDgv As DataGridView = CType(sender, DataGridView)
          
          If dragIndex > -1 AndAlso dragIndex < LclDgv.RowCount -1 Then
          
        2. 二是设置焦点到当前行和第一个单元格:

          LclDgv.Rows.Insert(dragIndex, dragRow)
          
          LclDgv.Rows(fromIndex).Selected = False
          LclDgv.Rows(dragIndex).Selected = True
          
          For Each C As DataGridViewColumn In LclDgv.Columns
            LclDgv(C.Index, fromIndex).Selected = False
          Next
          
          LclDgv(0, dragIndex).Selected = True
          

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-07-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          • 1970-01-01
          相关资源
          最近更新 更多