使用数据源时Datagridview拖放行
Datagridview drag&drop rows when using datasource
我正在尝试启动我的第一个应用程序 运行,但我在 datagridview 控件中进行拖放操作时遇到困难。
我创建了一个连接了数据源的数据网格视图。
Public oBodyAssembly As New BindingList(Of BodyComponent)
DataGridView1.DataSource = oBodyAssembly
在此 DataSource 中,用户创建了新的 objects 并且这些对象显示在 datagridview 中.为了允许用户更正或更改他添加对象的初始顺序,我想让它们 拖放行 以重新排列对象在 网格中的位置 以及 DataSource.
我已经尝试了这个用 C# 编写的示例代码并将其更改为 VB.NET,它的工作原理是我可以确定我拖动的行并确定放置的位置。
Link to the example code
但是随后示例中的代码插入了一个新行并删除了旧行。这对我不起作用。删除工作正常,对象也从我的 DataSource 中删除。另一方面,新行的插入不会。
我的 数据源 是一个 BindingList(Of BodyComponent)
它只包含 从 BodyComponent
派生的对象 class.
我怎样才能让这个操作起作用?我卡住了..
这是我到目前为止的拖放操作代码。
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
添加:在列表中创建对象的方法。
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
首先,由于无法对 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 的非行区域(empty/open 部分)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
,它测试非行区域的点击,并且仅在鼠标移动并按下左键时才开始拖动。它还拒绝拖放 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
结果:
提到的"non row"区域是黄色区域。
我正在尝试启动我的第一个应用程序 运行,但我在 datagridview 控件中进行拖放操作时遇到困难。
我创建了一个连接了数据源的数据网格视图。
Public oBodyAssembly As New BindingList(Of BodyComponent)
DataGridView1.DataSource = oBodyAssembly
在此 DataSource 中,用户创建了新的 objects 并且这些对象显示在 datagridview 中.为了允许用户更正或更改他添加对象的初始顺序,我想让它们 拖放行 以重新排列对象在 网格中的位置 以及 DataSource.
我已经尝试了这个用 C# 编写的示例代码并将其更改为 VB.NET,它的工作原理是我可以确定我拖动的行并确定放置的位置。 Link to the example code
但是随后示例中的代码插入了一个新行并删除了旧行。这对我不起作用。删除工作正常,对象也从我的 DataSource 中删除。另一方面,新行的插入不会。
我的 数据源 是一个 BindingList(Of BodyComponent)
它只包含 从 BodyComponent
派生的对象 class.
我怎样才能让这个操作起作用?我卡住了..
这是我到目前为止的拖放操作代码。
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
添加:在列表中创建对象的方法。
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
首先,由于无法对 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 的非行区域(empty/open 部分)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
,它测试非行区域的点击,并且仅在鼠标移动并按下左键时才开始拖动。它还拒绝拖放 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
结果:
提到的"non row"区域是黄色区域。