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状态的行,但这种方式有两个明显的问题:
- Deleted状态的行没有Current版本的数据,绑定列时会显示空值,需要额外处理绑定Original版本的值,非常繁琐;
- Deleted状态的行无法再被编辑,用户无法撤销删除操作(除非调用
row.RejectChanges(),但这会直接恢复行状态,不符合"待删除"的暂存需求)。
因此自定义状态列的方案更灵活,完全符合你"暂存操作、支持撤销/应用"的设计思路。
内容的提问来源于stack exchange,提问作者vic
相关产品推荐
相关产品推荐

