Datagridview在使用数据源

时间:2016-03-16 13:24:46

标签: vb.net datagridview drag-and-drop datasource

我试图启动并运行我的第一个应用程序,但我在 datagridview 控件中遇到了拖放操作。

我创建了一个数据源视图,其中有一个数据源连接到它。

Public oBodyAssembly As New BindingList(Of BodyComponent)
DataGridView1.DataSource = oBodyAssembly

在此数据源中,用户会创建新的对象,这些内容会显示在 datagridview 中。为了允许用户更正或改变他添加对象的初始顺序,我想让他们拖放行来重新排列网格中对象的位置,以及在 DataSource

我已经尝试过这个用C#编写的代码示例并将其改为VB.NET,它的工作原理是我可以确定拖动的行并确定放置的位置。 Link to the example code

但是样本中的代码会插入一个新行并删除旧行。这对我不起作用。删除工作正常,该对象也从我的 DataSource 中删除。另一方面,新行的插入不会。

我的数据源BindingList(Of BodyComponent)它只包含来自BodyComponent派生的对象。

如何让此操作正常工作?我被卡住了..

这是我到目前为止拖放操作的代码。

    Public oRowIndexMouseDown As Integer
Public oRow As DataGridViewRow

Private Sub BodyAssemblyDrag_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles DataGridView1.MouseDown
    If DataGridView1.SelectedRows.Count = 1 Then
        If e.Button = MouseButtons.Left Then
            oRow = DataGridView1.SelectedRows(0)
            oRowIndexMouseDown = DataGridView1.SelectedRows(0).Index
            'Debug.Print("Row to move = " & oRowIndexMouseDown)

            DataGridView1.DoDragDrop(sender, DragDropEffects.Move)
        End If
    End If
End Sub

Private Sub BodyAssemblyDrag_dragenter(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragEnter
    If DataGridView1.SelectedRows.Count = 1 Then
        e.Effect = DragDropEffects.Move
    End If
End Sub

Private Sub BodyAssemblyDrag_dragdrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragDrop
    Dim oPoint As Point
    oPoint = DataGridView1.PointToClient(New Point(e.X, e.Y))

    Dim oRowIndexMouseDrop As Integer
    oRowIndexMouseDrop = DataGridView1.HitTest(oPoint.X, oPoint.Y).RowIndex

    'Debug.Print("Drop row @ " & oRowIndexMouseDrop)

    If Not oRowIndexMouseDrop = oRowIndexMouseDown Then
        'DataGridView1.Rows.RemoveAt(oRowIndexMouseDown)
        'DataGridView1.Rows.Insert(oRowIndexMouseDrop, oRow)
    End If
End Sub

Screenshot of winform

添加:在列表中创建对象的方法。

    Public oBodyAssembly As New List(Of BodyComponent)


Private Sub BTN_BODY_ADD_CILINDER_Click(sender As Object, e As EventArgs) Handles BTN_BODY_ADD_CILINDER.Click

    ' Create a new cylinder and add it into the oBodyAssembly
    Dim oCylinder As New Body_Cylinder
    oBodyAssembly.Add(oCylinder)

    ' Set the index number for this cylinder
    oCylinder.Index = oBodyAssembly.Count

    ' Set the component type
    oCylinder.Type = BodyComponent.BodyComponentType.Cylinder

End Sub

Private Sub BTN_BODY_ADD_CONE_Click(sender As Object, e As EventArgs) Handles BTN_BODY_ADD_CONE.Click

    ' Create a new cone and add it into the oBodyAssembly
    Dim oCone As New Body_Cone
    oBodyAssembly.Add(oCone)

    ' Set the index number for this cylinder
    oCone.Index = oBodyAssembly.Count

    ' Set the component type
    oCone.Type = BodyComponent.BodyComponentType.Cone_reduction

End Sub

类:

Public Class BodyComponent

' Basic properties that are required for all of the bodycompenents
' regardless of the type.
Public Property Index() As Double
Public Property Type() As BodyComponentType
Public Property Height() As Double
Public Property Thickness() As Double
Public Property Elevation() As Double
Private Property Mass() As Double

' Type Enum that defines what kind of body component is created.
Public Enum BodyComponentType
    Cylinder = 0001
    Cone_reduction = 0002
End Enum End Class

派生对象(锥体相同)

Public Class Body_Cylinder

' Get the base properties
Inherits BodyComponent

' Set new properties that are only required for cylinders
Public Property Segments() As Integer
Public Property LW_Orientation() As Double End Class

1 个答案:

答案 0 :(得分:1)

首先,由于无法对BindingList进行排序或排序(不重新创建整个集合),我会使用简单的List(Of T)BindingSource

' Form level declarations:
Private Animals As List(Of AnimalEx)
Private BSAnimal As BindingSource

然后,一旦创建了列表:

Animals = New List(Of AnimalEx)
' add Animals aka BodyComponent objects, then...
BSAnimal = New BindingSource(Animals, Nothing)
dgv.DataSource = BSAnimal

您必须学习一些管理数据的新方法。从现在开始,List保存数据,但BindingSource提供绑定功能,您可以对List执行某些操作,有些则通过BindingSource执行。

对于行拖放,this answer中的代码是一个不错的起点,但有一些缺点。它没有考虑到a)绑定的DGV,b)用户试图拖动NewRow,c)用户点击DGV的非行区域(空/开放部分)d)允许鼠标执行其他操作,如调整列大小。我修复了这些,但可能还有其他鼠标操作可以免除。

' Form-level declarations
Private fromIndex As Integer = -1
Private bMouseDn As Boolean = False
Private MouseDnPt As Point = Point.Empty

Private Sub dgv_DragOver(sender As Object, e As DragEventArgs) Handles dgv.DragOver
    e.Effect = DragDropEffects.Move
End Sub

Private Sub dgv_MouseDown(sender As Object, e As MouseEventArgs) Handles dgv.MouseDown
    bMouseDn = (e.Button = Windows.Forms.MouseButtons.Left)
End Sub

Private Sub dgv_MouseMove(sender As Object, e As MouseEventArgs) Handles dgv.MouseMove
    If bMouseDn Then
        ' first time, just grab the start location
        If (MouseDnPt = Point.Empty) Then
            MouseDnPt = e.Location
            Exit Sub
        End If
    End If
    If bMouseDn AndAlso MouseDnPt <> Point.Empty Then
        Dim hitTst = dgv.HitTest(e.X, e.Y)
        If hitTst IsNot Nothing AndAlso fromIndex = -1 AndAlso hitTst.RowIndex > -1 Then
            fromIndex = hitTst.RowIndex

            If dgv.Rows(fromIndex).IsNewRow = False Then
                dgv.DoDragDrop(dgv.Rows(fromIndex), DragDropEffects.Move)
            End If
        End If
    End If
End Sub

Private Sub dgv_MouseUp(sender As Object, e As MouseEventArgs) Handles dgvDD.MouseUp
    If bMouseDn AndAlso (e.Button = Windows.Forms.MouseButtons.Left) Then
        bMouseDn = False
    End If
End Sub

我使用一个简单的Point代替Rectangle,它测试非行区域点击,只在鼠标移动并且向左按下按钮时开始拖动。它也拒绝DragDrop NewRow。

与原始版本一样,它会拖动DataGridViewRow。但由于我们希望(必须)更改DataSource,而不是DGV行,我们必须从DataSource获取项目:

Private Sub dgv_DragDrop(sender As Object, e As DragEventArgs) Handles dgv.DragDrop

    Dim p As Point = dgv.PointToClient(New Point(e.X, e.Y))
    Dim dragIndex = dgv.HitTest(p.X, p.Y).RowIndex
    If (e.Effect = DragDropEffects.Move) Then
        ' cast to a row
        Dim dragRow As DataGridViewRow = CType(e.Data.GetData(GetType(DataGridViewRow)), 
                                  DataGridViewRow)
        ' get related Animal object
        Dim a As AnimalEx = CType(dragRow.DataBoundItem, AnimalEx)

        ' manipulate DataSource:
        BSAnimal.RemoveAt(fromIndex)
        BSAnimal.Insert(dragIndex, a)

        ' if the DGV is SingleSelect, you may want:
        'dgv.Rows(dragIndex).Selected = True

        ' we are done dragging
        bMouseDn = False
        fromIndex = -1
        MouseDnPt = Point.Empty
    End If

End Sub

结果:

enter image description here enter image description here

提到的“非行”区域是黄色区域。