Andre の回答には、取得した座標が DataGrid の行ヘッダーと列ヘッダーを考慮していないため、小さな間違いがあります。少なくとも、Visual Basic でソリューションを実装したときはそうでした。
大規模な DataGrid を考慮して、示されている例を変更することもできます。そこにある制限はスクロール ビューに基づいているように思われるので、この修正の 2 つの実装を示します。
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
ScrollViewer.HorizontalOffset プロパティはデバイスに依存しないピクセルで値を返すことに注意してください。そのため、列をループする前に位置を一度オフセットするだけです。
CanContentScroll = True の場合、 ScrollViewer.VerticalOffset プロパティは項目数を返すことに注意してください。したがって、私の例では、各ループで、1 つの項目 (DataGridRow) の高さだけカウンターをオフセットします。CanContentScroll = False の場合、列インデックス ループの場合と同様に処理できます。
Visual Basic の .Net 4.0 の DataGrid で行定義を見つけることができませんでしたが、次のサポート関数は 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
Visual Basic の FindVisualChild 関数:
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