WPF获取DataGridCheckBoxColumn单元格值时遇空引用异常求助
问题:WPF DataGrid遍历到第29行时触发NullReferenceException
尝试遍历WPF应用中DataGrid的每一行,获取DataGridCheckBoxColumn的单元格值,参考示例代码后,运行到第28行正常,但第29行抛出System.NullReferenceException: 'Object reference not set to an instance of an object.'异常。DataGrid实际有约89行数据,代码曾几次正常返回所有值,但现在每次运行都会报错。
相关代码
XAML代码
<DataGrid x:Name="modelDataGrid" Margin="30,85,30,60" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn x:Name="RefDes" Header="Ref Des" Binding="{Binding RefDes}"/> <DataGridTextColumn x:Name="RenPartNumber" Header="Renishaw Part Number" Binding="{Binding RenPartNum}"/> <DataGridTextColumn x:Name="FileLocation" Header="File Location" Binding="{Binding FileLocation}"/> <DataGridTextColumn x:Name="FileStatus" Header="File Status" Binding="{Binding FileStatus}"/> <DataGridTextColumn x:Name="PartClass" Header="Part Class" Binding="{Binding PartClass}"/> <DataGridTextColumn x:Name="PartDescription" Header="Part Description" Binding="{Binding PartDescription}"/> <DataGridCheckBoxColumn x:Name="IncludeFolder" Header="Include in folder"/> </DataGrid.Columns> </DataGrid>
按钮点击事件C#代码
private void btnGenerateModel_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Make sure you have downloaded the most up to date TFS folder before continuing"); //Trace.WriteLine(modelDataGrid.Items.Count); for (int i = 0; i < modelDataGrid.Items.Count - 1; i++) { DataGridCell cell = GetCell(i, 6); Trace.WriteLine(cell.Content); } }
辅助C#代码
public DataGridCell GetCell(int row, int column) { DataGridRow rowData = GetRow(row); Trace.WriteLine(row); //Trace.WriteLine(rowData.ToString()); if (rowData != null) { DataGridCellsPresenter cellPresenter = GetVisualChild<DataGridCellsPresenter>(rowData); DataGridCell cell = (DataGridCell)cellPresenter.ItemContainerGenerator.ContainerFromIndex(column); if (cell == null) { modelDataGrid.ScrollIntoView(rowData, modelDataGrid.Columns[column]); cell = (DataGridCell)cellPresenter.ItemContainerGenerator.ContainerFromIndex(column); } return cell; } return null; } public DataGridRow GetRow(int index) { DataGridRow row = (DataGridRow)modelDataGrid.ItemContainerGenerator.ContainerFromIndex(index); Trace.WriteLine(row); if (row == null) { modelDataGrid.UpdateLayout(); modelDataGrid.ScrollIntoView(modelDataGrid.Items[index]); row = (DataGridRow)modelDataGrid.ItemContainerGenerator.ContainerFromIndex(index); } return row; } public static T GetVisualChild<T>(Visual parent) where T : Visual { T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < numVisuals; i++) { Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); child = v as T; if (child == null) { child = GetVisualChild<T>(v); } if (child != null) { break; } } return child; }
Trace输出(异常出现前最后几行)
System.Windows.Controls.CheckBox Content: IsChecked:False System.Windows.Controls.DataGridRow 28 System.Windows.Controls.CheckBox Content: IsChecked:False 29
从输出可见,第28行的DataGridRow是有效对象,但第29行的rowData为空。
解决方案
1. 修正循环边界
当前循环条件i < modelDataGrid.Items.Count - 1会跳过最后一行,先改为i < modelDataGrid.Items.Count确保遍历所有行,排除边界计算错误的可能。
2. 提升GetRow方法的可靠性
WPF的ItemContainerGenerator仅为可见行生成容器,滚动后才会生成新行。原方法的ScrollIntoView可能因UI线程延迟未及时生成容器,可添加强制渲染等待:
public DataGridRow GetRow(int index) { if (index < 0 || index >= modelDataGrid.Items.Count) return null; DataGridRow row = (DataGridRow)modelDataGrid.ItemContainerGenerator.ContainerFromIndex(index); if (row == null) { modelDataGrid.ScrollIntoView(modelDataGrid.Items[index]); modelDataGrid.UpdateLayout(); // 强制等待UI渲染完成 Dispatcher.Invoke(() => {}, DispatcherPriority.Render); row = (DataGridRow)modelDataGrid.ItemContainerGenerator.ContainerFromIndex(index); } return row; }
3. 采用MVVM绑定方式(推荐)
直接操作可视化树容易受UI容器生成时机影响,更可靠的方式是绑定数据模型:
- 为数据模型添加
bool类型属性(如IsIncludeInFolder) - 修改XAML中
DataGridCheckBoxColumn的绑定:<DataGridCheckBoxColumn x:Name="IncludeFolder" Header="Include in folder" Binding="{Binding IsIncludeInFolder}"/> - 直接遍历数据源获取值,无需操作UI元素:
private void btnGenerateModel_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Make sure you have downloaded the most up to date TFS folder before continuing"); foreach (var item in modelDataGrid.Items) { var dataItem = item as YourDataModelType; // 替换为实际数据模型类型 if (dataItem != null) { Trace.WriteLine(dataItem.IsIncludeInFolder); } } }
这种方式完全避开可视化树依赖,是WPF的推荐做法,不会出现空引用异常。
内容的提问来源于stack exchange,提问作者ProgramMasher
相关产品推荐
相关产品推荐

