You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();

问题根源

  1. 类型不匹配:填充DataGrid的是LINQ查询生成的匿名类型对象,但删除代码中强行将SelectedItem转换为Curso类,转换结果为null,访问idInscrito时触发空引用异常。
  2. 查询条件错误:删除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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:47:52