如何在 DataGridView 中筛选 Payment 行并求和
支付老李
结论
不必遍历所有列。逐行检查描述列,找到包含 Payment 的行后,读取该行的金额列,将其转换为 decimal 并累加。最后在按钮单击事件中把总额写入 TextBox。
private void btnCalculate_Click(object sender, EventArgs e)
{
decimal total = 0m;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
// 忽略 DataGridView 底部用于新增数据的空白行
if (row.IsNewRow)
continue;
string description = Convert.ToString(row.Cells[0].Value);
if (description.IndexOf(
"Payment",
StringComparison.OrdinalIgnoreCase) < 0)
{
continue;
}
object value = row.Cells[1].Value;
if (value == null || value == DBNull.Value)
continue;
if (decimal.TryParse(value.ToString(), out decimal amount))
{
total += amount;
}
}
textBox1.Text = total.ToString("0.##");
}
按照题目中的数据计算,total 最终是 173.8。
为什么不需要内层循环
数据结构是固定的:
- 第一列是描述;
- 第二列是金额。
每行只需检查 Cells[0],匹配成功后再读取 Cells[1]。原代码中的内层 for 循环还会检查其他列,没有必要,而且列顺序调整后容易读错单元格。
如果已经为 DataGridView 的列设置了 Name,建议直接使用列名,代码更容易理解:
string description = Convert.ToString(row.Cells["Description"].Value);
object value = row.Cells["Amount"].Value;
金额列存储的是数值时
金额单元格最好直接存储 decimal,美元符号通过单元格格式显示。这样求和时不需要处理 $ 等货币符号:
private void btnCalculate_Click(object sender, EventArgs e)
{
decimal total = 0m;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.IsNewRow)
continue;
string description =
Convert.ToString(row.Cells["Description"].Value);
if (description.IndexOf(
"Payment",
StringComparison.OrdinalIgnoreCase) < 0)
{
continue;
}
object value = row.Cells["Amount"].Value;
if (value == null || value == DBNull.Value)
continue;
try
{
total += Convert.ToDecimal(value);
}
catch (FormatException)
{
// 当前单元格不是有效金额,可按业务需求记录或提示
}
catch (InvalidCastException)
{
// 当前值无法转换为 decimal
}
}
textBox1.Text = total.ToString("0.##");
}
可以把金额列设置为货币显示格式:
dataGridView1.Columns["Amount"].DefaultCellStyle.Format = "C";
这项设置只影响显示,不会把底层的 decimal 数据转换成字符串。
单元格中确实包含 $ 时
如果金额单元格保存的是 "$45.9" 这类文本,就需要按货币格式解析:
using System.Globalization;
private void btnCalculate_Click(object sender, EventArgs e)
{
decimal total = 0m;
CultureInfo currencyCulture = CultureInfo.GetCultureInfo("en-US");
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.IsNewRow)
continue;
string description = Convert.ToString(row.Cells[0].Value);
if (description.IndexOf(
"Payment",
StringComparison.OrdinalIgnoreCase) < 0)
{
continue;
}
string amountText = Convert.ToString(row.Cells[1].Value);
if (decimal.TryParse(
amountText,
NumberStyles.Currency,
currencyCulture,
out decimal amount))
{
total += amount;
}
}
textBox1.Text = total.ToString("C", currencyCulture);
}
使用标准货币格式后,结果通常会显示为:
$173.80
如果必须显示成示例中的 $173.8,可以这样写:
textBox1.Text = "$" + total.ToString(
"0.##",
CultureInfo.InvariantCulture);
注意事项
row.IsNewRow用于排除允许用户新增行时出现在表格底部的空白行。- 金额应尽量存储为
decimal,不要把货币符号和数值一起保存为字符串。 OrdinalIgnoreCase能同时匹配Payment、payment等不同大小写形式。- 如果描述必须以
Payment开头,可以改用StartsWith,以免匹配到其他仅在中间包含该单词的描述:
if (description.StartsWith(
"Payment",
StringComparison.OrdinalIgnoreCase))
{
// 累加金额
}
decimal.TryParse解析失败时不会抛出异常,适合处理可能包含空值或无效文本的表格数据。
备注:内容仅供参考。
