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

WPF DataGrid中如何保留并显示标记为待删除状态的DataTable行

解决DataGrid中保留待删除行可见的问题

你遇到的核心问题是调用row.Delete()后,DataRow的状态变为Deleted,而默认的DataView会过滤掉这类行(因为默认RowStateFilter是DataViewRowState.CurrentRows),导致它们从DataGrid中消失。要实现"待删除行保留显示,直到用户确认应用更改"的需求,最稳妥的方案是自定义行状态标记,而不是直接依赖DataRow的原生RowState,具体步骤如下:

一、添加自定义行状态列

首先给你的DataTable新增一个用来标记行状态的列,比如命名为RowStatus,用来区分"正常"、"待添加"、"待修改"、"待删除"四种状态:

// 在初始化DataTable时添加状态列
dataTable.Columns.Add("RowStatus", typeof(string));

// 给现有行初始化状态为"Normal"
foreach (DataRow row in dataTable.Rows)
{
    row["RowStatus"] = "Normal";
}

二、替换原生Delete操作,标记待删除状态

当用户触发删除行操作时,不要直接调用row.Delete(),而是将该行的RowStatus设为PendingDelete:

// 假设你获取到了用户选中的行selectedRow
if (selectedRow != null)
{
    selectedRow["RowStatus"] = "PendingDelete";
}

这样行不会立即从DataGrid中消失,只是被标记为待删除状态。

三、更新样式触发器,绑定自定义状态

把你原来基于Row.RowState的触发器,改成绑定自定义的RowStatus列,这样就能正确显示待删除行的红色背景:

<!-- 待删除行样式 -->
<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=Row.RowStatus}" Value="PendingDelete" />
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsSelected}" Value="False" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <Setter Property="Background" Value="IndianRed" TargetName="DGR_Border"/>
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="FontWeight" Value="Bold"/>
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

<!-- 补充待添加、待修改行的样式触发器 -->
<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=Row.RowStatus}" Value="PendingAdd" />
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsSelected}" Value="False" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <Setter Property="Background" Value="LightGreen" TargetName="DGR_Border"/>
        <Setter Property="Foreground" Value="Black"/>
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=Row.RowStatus}" Value="PendingUpdate" />
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsSelected}" Value="False" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <Setter Property="Background" Value="Orange" TargetName="DGR_Border"/>
        <Setter Property="Foreground" Value="Black"/>
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

四、处理添加和修改的状态标记

  • 添加行:当用户新增行时,直接将新行的RowStatus设为PendingAdd:
DataRow newRow = dataTable.NewRow();
// 初始化新行的其他列数据
newRow["RowStatus"] = "PendingAdd";
dataTable.Rows.Add(newRow);
  • 修改行:可以通过监听DataTable的RowChanged事件,自动将修改过的行标记为PendingUpdate(排除待添加和待删除的行):
dataTable.RowChanged += (sender, e) =>
{
    string currentStatus = e.Row["RowStatus"].ToString();
    if (currentStatus != "PendingAdd" && currentStatus != "PendingDelete")
    {
        e.Row["RowStatus"] = "PendingUpdate";
    }
};

五、实现撤销和应用更改的逻辑

1. 撤销更改

将所有标记为待操作的行状态重置为Normal:

foreach (DataRow row in dataTable.Rows)
{
    string status = row["RowStatus"].ToString();
    if (status == "PendingAdd" || status == "PendingUpdate" || status == "PendingDelete")
    {
        row["RowStatus"] = "Normal";
        // 如果是待添加的行,直接移除(因为还没提交到数据源)
        if (status == "PendingAdd")
        {
            row.Delete();
        }
    }
}
dataTable.AcceptChanges();

2. 应用更改

真正执行删除、提交新增和修改的行:

// 倒序删除待删除的行,避免索引偏移问题
for (int i = dataTable.Rows.Count - 1; i >= 0; i--)
{
    DataRow row = dataTable.Rows[i];
    if (row["RowStatus"].ToString() == "PendingDelete")
    {
        row.Delete();
    }
}

// 重置其他行的状态为Normal
foreach (DataRow row in dataTable.Rows)
{
    if (row["RowStatus"].ToString() != "Normal")
    {
        row["RowStatus"] = "Normal";
    }
}

// 提交所有更改到数据源
dataTable.AcceptChanges();

为什么不推荐直接修改DataView的RowStateFilter?

你可能会想到通过设置dataView.RowStateFilter = DataViewRowState.All来显示Deleted状态的行,但这种方式有两个明显的问题:

  1. Deleted状态的行没有Current版本的数据,绑定列时会显示空值,需要额外处理绑定Original版本的值,非常繁琐;
  2. Deleted状态的行无法再被编辑,用户无法撤销删除操作(除非调用row.RejectChanges(),但这会直接恢复行状态,不符合"待删除"的暂存需求)。

因此自定义状态列的方案更灵活,完全符合你"暂存操作、支持撤销/应用"的设计思路。

内容的提问来源于stack exchange,提问作者vic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 17:47:30