WPF DataGrid:高效获取单元格所在行索引的方法
Nice find! You’re right that most common solutions for grabbing a row index from DataGridCellInfo rely on slow linear searches (like Items.IndexOf(cellInfo.Item)), which get painful with large datasets. Leveraging the internal ItemInfo property is a smart way to skip that overhead—here’s how to implement it properly:
How It Works
The DataGridCellInfo internally stores an ItemInfo object that tracks the exact index of the row it belongs to. Since this is a non-public property, we’ll use reflection to access it, letting us pull the index in O(1) time instead of the O(n) cost of linear searches.
Step-by-Step Implementation
Create an extension method to make this reusable across your project:
using System; using System.Reflection; using System.Windows.Controls; public static class DataGridCellInfoExtensions { public static int GetRowIndex(this DataGridCellInfo cellInfo) { // Guard against invalid cell info if (!cellInfo.IsValid) throw new ArgumentException("The provided DataGridCellInfo is invalid.", nameof(cellInfo)); // Retrieve the non-public ItemInfo property var itemInfoProperty = typeof(DataGridCellInfo).GetProperty( "ItemInfo", BindingFlags.NonPublic | BindingFlags.Instance); if (itemInfoProperty == null) throw new InvalidOperationException("Could not access the internal ItemInfo property. This may be due to a WPF version change."); var itemInfo = itemInfoProperty.GetValue(cellInfo); if (itemInfo == null) return -1; // Get the Index field from the ItemInfo object var indexField = itemInfo.GetType().GetField( "Index", BindingFlags.Public | BindingFlags.Instance); if (indexField == null) throw new InvalidOperationException("Could not access the Index field in ItemInfo. This may be due to a WPF version change."); return (int)indexField.GetValue(itemInfo); } }
Usage Example
Just call the extension method on any valid DataGridCellInfo:
DataGridCellInfo selectedCell = myDataGrid.SelectedCells[0]; int rowIndex = selectedCell.GetRowIndex();
Important Caveats
Since we’re tapping into internal WPF APIs:
- Version Compatibility: Microsoft might rename, modify, or remove
ItemInfoor theIndexfield in future .NET/WPF updates. Always test this code when upgrading your framework version. - Fallback Plan: For robustness, add a fallback to the linear search method if reflection fails. Here’s how to extend the method:
public static int GetRowIndexSafe(this DataGridCellInfo cellInfo, DataGrid dataGrid) { try { return cellInfo.GetRowIndex(); } catch (Exception) { // Fall back to the standard (slower) method if reflection fails return dataGrid?.Items.IndexOf(cellInfo.Item) ?? -1; } }
Why This Is Better
- Performance: Directly accessing the stored index avoids iterating through the entire
Itemscollection, which is a massive win for large DataGrids with hundreds or thousands of rows. - Accuracy: Unlike visual tree traversal workarounds, this uses the same index the DataGrid internally tracks, so it’s less prone to errors from virtualization or UI state changes.
内容的提问来源于stack exchange,提问作者melmi

