Câu trả lời của Andre có một sai lầm nhỏ do tọa độ thu được không tính đến tiêu đề hàng và cột trong DataGrid. Ít nhất đây là trường hợp khi tôi thực hiện các giải pháp trong Visual Basic.
Bạn cũng có thể sửa đổi các ví dụ được hiển thị để giải thích cho một DataGrid lớn. Dường như với tôi rằng giới hạn có được dựa trên quan điểm cuộn, vì vậy tôi thấy hai triển khai điều chỉnh này:
Private Sub myGrid_MouseMove(sender As Object, e As MouseEventArgs) Handles myGrid.MouseMove
Dim total As Double
Dim myScrollViewer As ScrollViewer = FindVisualChild(Of ScrollViewer)(myGrid)
Dim cursorPositionX = e.GetPosition(myGrid).X
Dim columnIndex As Integer = -1
total = 0
'Horizontal offset'
Dim rowHeaders As DataGridRowHeader = FindVisualChild(Of DataGridRowHeader)(myGrid)
cursorPositionX -= (rowHeaders.ActualWidth - myScrollViewer.HorizontalOffset)
For Each column As DataGridColumn In myGrid.Columns
If cursorPositionX < total Then Exit For
columnIndex += 1
total += column.Width.DisplayValue
Next
Dim cursorPositionY = e.GetPosition(myGrid).Y
Dim rowIndex As Integer = -1
total = 0
'Vertical offset'
Dim originalOffset As Double = myScrollViewer.VerticalOffset
Dim colHeadersPresenter As DataGridColumnHeadersPresenter = FindVisualChild(Of DataGridColumnHeadersPresenter)(myGrid)
cursorPositionY -= colHeadersPresenter.ActualHeight
For Each row As System.Data.DataRowView In myGrid.Items
If cursorPositionY < total Then Exit For
rowIndex += 1
Dim dgRow As DataGridRow = GetRowByIndex(myGrid, rowIndex)
total += dgRow.ActualHeight
'GetRowByIndex will scroll the view to bring the DataGridRow of interest into view, which throws off the counter. This adjusts for that'
myGrid.UpdateLayout()
If Not myScrollViewer.VerticalOffset = originalOffset Then myGrid.ScrollIntoView(myGrid.Items(CInt(myScrollViewer.ViewportHeight + originalOffset - 1)))
myGrid.UpdateLayout()
If myScrollViewer.VerticalOffset > rowIndex Then cursorPositionY += dgRow.ActualHeight
Next
End Sub
Lưu ý rằng ScrollViewer.HorizontalOffset Property trả về một giá trị trong Pixels độc lập thiết bị, vì vậy tôi chỉ bù đắp vị trí của tôi một lần trước khi lặp qua các cột.
Lưu ý rằng số ScrollViewer.VerticalOffset Property trả về số mục nếu CanContentScroll = True. Vì vậy, trong ví dụ của tôi, trên mỗi vòng lặp tôi bù đắp bộ đếm theo chiều cao của một mục (DataGridRow). Nếu CanContentScroll = False, thì nó có thể được xử lý như trong trường hợp vòng lặp chỉ mục cột.
tôi không thể tìm thấy định nghĩa dòng trong DataGrid cho Net 4.0 trong Visual Basic, nhưng chức năng hỗ trợ sau đây sẽ giúp cho việc thu thập DataGridRow:
Function GetRowByIndex(ByVal p_dataGrid As DataGrid,
ByVal p_index As Integer) As DataGridRow
Dim row As DataGridRow
row = CType(p_dataGrid.ItemContainerGenerator.ContainerFromIndex(p_index), DataGridRow)
If IsNothing(row) Then
'May be virtualized, bring into view and try again.'
p_dataGrid.UpdateLayout()
p_dataGrid.ScrollIntoView(p_dataGrid.Items(p_index))
row = CType(p_dataGrid.ItemContainerGenerator.ContainerFromIndex(p_index), DataGridRow)
End If
Return row
End Function
Và chức năng FindVisualChild trong Visual Basic:
Function FindVisualChild(Of childItem As DependencyObject)(ByVal p_obj As DependencyObject) As childItem
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(p_obj) - 1
Dim child As DependencyObject = VisualTreeHelper.GetChild(p_obj, i)
If child IsNot Nothing AndAlso TypeOf child Is childItem Then
Return CType(child, childItem)
Else
Dim childOfChild As childItem = FindVisualChild(Of childItem)(child)
If childOfChild IsNot Nothing Then
Return childOfChild
End If
End If
Next i
Return Nothing
End Function
Nhìn vào chức năng kéo/thả trong FluidKit. Bạn sẽ không phải lo lắng về hacky shnit như thế này. – Will
Tôi đã sử dụng FluidKit, rằng 'MouseMove' thực sự là 'OnDropCompleted' và vị trí chuột thực sự là 'dropPoint' - Tôi muốn có thể thả vào các ô cụ thể trên bảng mà tôi chưa thể nhận được đang làm việc. – Wilka