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

Visual Studio 2017 C#:DataGridView失焦时校验列D与SI表重复

搞定DataGridView录入校验与数据保存的方案

我来帮你一步步解决这个问题,结合你用VS2017 C#开发、SQL数据库包含SI和SIC表的场景,直接上可落地的代码和步骤:

一、实现D列失焦时的重复校验

核心思路是监听DataGridView的单元格离开事件,当用户在D列输入完移开焦点时,去SI表查询这个值是否存在。

1. 先写个复用性强的校验方法

封装一个检查值是否在SI表存在的方法,一定要用参数化查询避免SQL注入:

private bool IsValueDuplicateInSI(string inputValue)
{
    // 替换成你实际的数据库连接字符串
    string connString = "Server=你的服务器名;Database=你的库名;Integrated Security=True;";
    string checkQuery = "SELECT COUNT(*) FROM SI WHERE D列的实际名称 = @InputValue";

    using (SqlConnection conn = new SqlConnection(connString))
    {
        SqlCommand cmd = new SqlCommand(checkQuery, conn);
        cmd.Parameters.AddWithValue("@InputValue", inputValue.Trim());
        
        conn.Open();
        int matchCount = (int)cmd.ExecuteScalar();
        // 有匹配就返回true,说明值重复了
        return matchCount > 0;
    }
}

注意:把D列的实际名称替换成你SI表中对应的列名,别直接用模糊的"D列"哦!

2. 绑定单元格离开事件

在窗体的构造函数或者Load事件里,给DataGridView挂上CellLeave事件:

public YourFormName() // 替换成你的窗体类名
{
    InitializeComponent();
    // 假设你的DataGridView叫dataGridView_SIC
    dataGridView_SIC.CellLeave += DataGridView_SIC_CellLeave;
}

然后实现事件处理逻辑,判断当前离开的是不是D列(列索引从0开始,比如D是第3列就写3,根据你的实际列位置调整):

private void DataGridView_SIC_CellLeave(object sender, DataGridViewCellEventArgs e)
{
    // 排除表头和未编辑的新行
    if (e.RowIndex < 0 || dataGridView_SIC.Rows[e.RowIndex].IsNewRow)
        return;

    // 检查当前离开的是不是D列(这里假设列索引是3,自己根据实际修改)
    if (e.ColumnIndex == 3)
    {
        DataGridViewCell currentCell = dataGridView_SIC.Rows[e.RowIndex].Cells[e.ColumnIndex];
        string inputVal = currentCell.Value?.ToString().Trim();

        if (!string.IsNullOrEmpty(inputVal))
        {
            if (IsValueDuplicateInSI(inputVal))
            {
                MessageBox.Show($"值「{inputVal}」已经在SI表存在啦,请重新输入!", "重复提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                // 强制让单元格重新获得焦点,不让用户跳过修改
                dataGridView_SIC.CurrentCell = currentCell;
            }
        }
    }
}

二、实现DataGridView数据保存到SIC表

分两种场景提供方案,选适合你的就行:

1. 用TableAdapter保存(推荐,省心高效)

如果你已经通过VS的数据源向导创建了DataSet并关联了SIC表,直接调用自动生成的Update方法即可:

private void btnSave_Click(object sender, EventArgs e)
{
    try
    {
        // 先结束当前编辑,确保所有单元格的修改都提交到DataSet
        dataGridView_SIC.EndEdit();
        // 替换成你的TableAdapter和DataSet名称
        sicTableAdapter.Update(yourDataSet.SIC);
        MessageBox.Show("数据保存成功!", "搞定啦", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (Exception ex)
    {
        // 捕获唯一约束异常,给用户更明确的提示
        if (ex.Message.Contains("UNIQUE KEY"))
        {
            MessageBox.Show("有重复值哦,数据库不允许保存!", "保存失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            MessageBox.Show($"保存出错:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

2. 手动写保存逻辑(未使用DataSet的情况)

如果是自己手动处理数据,遍历DataGridView的行来执行插入或更新操作:

private void btnSave_Click(object sender, EventArgs e)
{
    string connString = "你的数据库连接字符串";
    using (SqlConnection conn = new SqlConnection(connString))
    {
        conn.Open();
        foreach (DataGridViewRow row in dataGridView_SIC.Rows)
        {
            // 跳过新增的空行
            if (row.IsNewRow) continue;

            // 获取每行的数据,替换成你的实际列名
            string colA = row.Cells["列A名称"].Value?.ToString() ?? "";
            string colD = row.Cells["列D名称"].Value?.ToString() ?? "";
            // 其他列同理,比如int类型列:int colB = int.TryParse(row.Cells["列B"].Value?.ToString(), out var val) ? val : 0;

            // 假设SIC表有主键ID,判断是新增还是更新
            int? rowId = row.Cells["ID"].Value as int?;
            if (rowId == null || rowId == 0)
            {
                // 新增记录
                string insertSql = "INSERT INTO SIC (列A名称, 列D名称, ...) VALUES (@ColA, @ColD, ...)";
                SqlCommand cmd = new SqlCommand(insertSql, conn);
                cmd.Parameters.AddWithValue("@ColA", colA);
                cmd.Parameters.AddWithValue("@ColD", colD);
                // 补充其他参数
                cmd.ExecuteNonQuery();
            }
            else
            {
                // 更新记录
                string updateSql = "UPDATE SIC SET 列A名称 = @ColA, 列D名称 = @ColD, ... WHERE ID = @RowId";
                SqlCommand cmd = new SqlCommand(updateSql, conn);
                cmd.Parameters.AddWithValue("@ColA", colA);
                cmd.Parameters.AddWithValue("@ColD", colD);
                cmd.Parameters.AddWithValue("@RowId", rowId);
                // 补充其他参数
                cmd.ExecuteNonQuery();
            }
        }
        conn.Close();
        MessageBox.Show("数据全部保存完成!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
}

三、额外实用提醒

  • 你提到之前设置了唯一约束,保存时如果SIC表的D列有重复,数据库会抛出异常,记得在catch块里针对性捕获,给用户明确提示
  • 要是数据量较大,校验时可以用异步查询避免UI卡顿,比如把校验方法放到Task.Run里:
private async void DataGridView_SIC_CellLeave(object sender, DataGridViewCellEventArgs e)
{
    // 前面的判断逻辑不变...
    if (!string.IsNullOrEmpty(inputVal))
    {
        bool isDuplicate = await Task.Run(() => IsValueDuplicateInSI(inputVal));
        if (isDuplicate)
        {
            MessageBox.Show($"值「{inputVal}」已经在SI表存在啦,请重新输入!", "重复提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            dataGridView_SIC.CurrentCell = currentCell;
        }
    }
}
  • 数据库连接字符串建议放到App.config里,别硬编码在代码中,方便后续维护

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:35:27