WPF DataGrid多表查询数据行删除空引用错误求助
WPF DataGrid多表关联数据删除解决方案
问题说明
使用WPF DataGrid展示两张表关联查询的数据时,无法正常删除行:单表数据删除逻辑可行,但多表场景下获取选中行的idInscrito值时抛出空引用错误,无法同时删除DataGrid行和数据库对应记录。
相关代码如下:
DataGrid的XAML代码
<DataGrid.Columns> <DataGridTextColumn Header="ID" Binding="{Binding idInscrito}" Width="120"/> <DataGridTextColumn Header="IdAlumno" Binding="{Binding IdAlum}" Width="120"/> <DataGridTextColumn Header="Matricula" Binding="{Binding matricula}" Width="150"/> <DataGridTextColumn Header="Apellido" Binding="{Binding apellido}" Width="250"/> <DataGridTextColumn Header="Nombre" Binding="{Binding nombre}" Width="150"/> <DataGridTemplateColumn> <DataGridTemplateColumn.HeaderTemplate> <DataTemplate> <TextBlock Text="Accion"/> </DataTemplate> </DataGridTemplateColumn.HeaderTemplate> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Button x:Name="btnBorrar" Cursor="Hand" Style="{StaticResource Boton}" Content="Borrar" Click="btnBorrar_Click"> <Button.Resources> <Style TargetType="Border"> <Setter Property="CornerRadius" Value="5"/> </Style> </Button.Resources> </Button> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns>
填充DataGrid的后台代码
var alumn = (from v in _db.inscritos join b in _db.alumnos on v.IdAlum equals b.IdAlum where v.idNivel == (int?)comboNivel.SelectedValue && v.idSec == (int?)comboSeccion.SelectedValue orderby b.apellido select new {v.idInscrito, v.IdAlum, v.matricula, b.apellido, b.nombre }).ToList(); GridInscritos.ItemsSource = alumn;
原删除按钮点击事件代码(存在问题)
// 此处强制转换为Curso类型会返回null,导致空引用错误 int id = (int)(GridInscritos.SelectedItem as Curso).idInscrito; var ins = _db.inscritos.Where(a => a.IdAlum == id).SingleOrDefault(); _db.inscritos.Remove(ins); _db.SaveChanges();
问题根源
- 类型不匹配:填充DataGrid的是LINQ查询生成的匿名类型对象,但删除代码中强行将
SelectedItem转换为Curso类,转换结果为null,访问idInscrito时触发空引用异常。 - 查询条件错误:删除
inscritos表数据时,用IdAlum作为匹配条件,这会删除所有关联同一学生的记录,而非当前选中的特定inscrito记录,应该用idInscrito作为唯一标识。
解决方法
方法一:使用动态类型临时修复(快速解决)
修改删除事件代码,通过dynamic类型访问匿名对象的属性,同时修正查询条件并同步更新DataGrid数据源:
private void btnBorrar_Click(object sender, RoutedEventArgs e) { var selectedItem = GridInscritos.SelectedItem; if (selectedItem == null) return; // 用dynamic访问匿名类型的属性 dynamic item = selectedItem; int idInscrito = item.idInscrito; // 根据idInscrito查找要删除的记录 var ins = _db.inscritos.Where(a => a.idInscrito == idInscrito).SingleOrDefault(); if (ins != null) { _db.inscritos.Remove(ins); _db.SaveChanges(); // 从DataGrid数据源中移除该行,刷新界面 var dataSource = GridInscritos.ItemsSource as List<dynamic>; if (dataSource != null) { dataSource.Remove(selectedItem); GridInscritos.Items.Refresh(); } } }
方法二:创建ViewModel类(类型安全,推荐)
定义一个专门的ViewModel类存储多表查询结果,避免匿名类型的类型转换问题:
1. 创建ViewModel类
public class InscritoAlumnoViewModel { public int idInscrito { get; set; } public int IdAlum { get; set; } public string matricula { get; set; } public string apellido { get; set; } public string nombre { get; set; } }
2. 修改填充DataGrid的代码
将LINQ查询的结果转换为ViewModel类型:
var alumn = (from v in _db.inscritos join b in _db.alumnos on v.IdAlum equals b.IdAlum where v.idNivel == (int?)comboNivel.SelectedValue && v.idSec == (int?)comboSeccion.SelectedValue orderby b.apellido select new InscritoAlumnoViewModel { idInscrito = v.idInscrito, IdAlum = v.IdAlum, matricula = v.matricula, apellido = b.apellido, nombre = b.nombre }).ToList(); GridInscritos.ItemsSource = alumn;
3. 修改删除事件代码
直接转换为ViewModel类型,类型安全且避免空引用:
private void btnBorrar_Click(object sender, RoutedEventArgs e) { var selectedItem = GridInscritos.SelectedItem as InscritoAlumnoViewModel; if (selectedItem == null) return; var ins = _db.inscritos.Where(a => a.idInscrito == selectedItem.idInscrito).SingleOrDefault(); if (ins != null) { _db.inscritos.Remove(ins); _db.SaveChanges(); // 同步移除DataGrid中的行 var dataSource = GridInscritos.ItemsSource as List<InscritoAlumnoViewModel>; if (dataSource != null) { dataSource.Remove(selectedItem); GridInscritos.Items.Refresh(); } } }
注意事项
- 确保DataGrid的数据源是可修改的集合(如
List<T>),如果用IEnumerable<T>需要先转换为List<T>才能移除元素。 - 删除数据库记录后必须同步更新DataGrid的数据源,否则界面不会自动刷新。
内容的提问来源于stack exchange,提问作者Formulaz5
相关产品推荐
相关产品推荐

