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

C#.NET结合SQL Server跨窗体给控件赋值报类型转换错误如何解决

问题描述

在使用.NET平台C#语言结合SQL Server开发WinForm应用时,需要实现以下功能:选中dgvTransactionTable数据表格的某一行后,查询对应id的交易记录,打开TransactionView窗体并将查询到的数据传递给该窗体的对应输入控件。初始实现代码如下:

private void UpdateTransaction(object sender, EventArgs e)
{
    if (this.dgvTransactionTable.SelectedRows.Count != 0)
    {
        DataGridViewRow row = this.dgvTransactionTable.SelectedRows[0];
        int id = Convert.ToInt32(row.Cells["id"].Value);
        SqlConnection con = new SqlConnection(connectionString);
        if (con.State == ConnectionState.Closed)
        {
            con.Open();
        }

        SqlCommand cmd = new SqlCommand("SELECT * FROM  transactions where id = '" + id + "'", con);
        SqlDataReader dt= cmd.ExecuteReader();
        if (dt.Read()) 
        {
            TransactionView transactionView = new TransactionView();
            transactionView.Show();
            transactionView.txtTransactionName = dt.GetValue(0).ToString();
            transactionView.cmbTransactionCategory = dt.GetValue(1).ToString();
            transactionView.dateTransaction = dt.GetValue(2).ToString();
            transactionView.txtTransactionName = dt.GetValue(3).ToString();
        }


    }
    else
    {
        MessageBox.Show("Please Choose a Row", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
}

运行代码时,窗体控件赋值段抛出类型转换错误,对应报错代码如下:

transactionView.txtTransactionName = dt.GetValue(0).ToString();
transactionView.cmbTransactionCategory = dt.GetValue(1).ToString();
transactionView.dateTransaction = dt.GetValue(2).ToString(); 
transactionView.txtTransactionName = dt.GetValue(3).ToString();

错误提示:"cannot convert type string to system.windows.forms.textbox"(无法将string类型转换为System.Windows.Forms.TextBox类型)

问题原因

报错核心是赋值逻辑错误:WinForm中的TextBox、ComboBox、DateTimePicker都属于控件类对象,不能直接将字符串赋值给控件变量本身,需要给控件对应的值属性赋值才能正常显示内容。
现有代码还存在以下隐患:

  • 字符串拼接SQL存在SQL注入风险
  • 数据库连接、SqlCommand、SqlDataReader对象未做资源释放,长期运行会引发数据库连接泄漏
  • 重复给txtTransactionName赋值,存在字段索引对应错误
  • 直接跨窗体访问控件不符合封装规范,WinForm默认生成的控件访问修饰符为private,正常场景下外部窗体无法直接访问
  • 给日期选择控件直接传递字符串,容易因系统区域格式差异导致转换失败
  • 用SELECT *配合序号索引取值,一旦表结构字段顺序调整,就会出现赋值错位问题
修复方案
  1. 修正控件赋值逻辑:
    • 文本框(TextBox)给Text属性赋字符串值
    • 下拉框(ComboBox)可通过Text属性设置显示文本,若绑定了数据源则优先通过SelectedValue匹配对应选项
    • 日期选择框(DateTimePicker)给Value属性赋DateTime类型值,不要直接传字符串
  2. 优化窗体传值方式:给TransactionView添加带参数的构造函数,在窗体内部完成控件赋值,避免跨窗体直接操作控件
  3. 替换字符串拼接SQL为参数化查询,用using语句自动释放数据库相关资源,改用字段名读取查询结果,避免索引错位

修复后代码

首先在TransactionView窗体类中添加带参数的构造函数:

// TransactionView窗体类内添加
public TransactionView(string transName, string category, DateTime transDate, decimal transAmount)
{
    InitializeComponent();
    // 本窗体内直接给控件属性赋值
    txtTransactionName.Text = transName;
    cmbTransactionCategory.Text = category;
    dateTransaction.Value = transDate;
    // 原代码重复给txtTransactionName赋值,第四个字段请根据实际业务替换为对应控件,示例为金额输入框
    txtTransAmount.Text = transAmount.ToString("0.00");
}

再修改调用方的按钮事件逻辑:

private void UpdateTransaction(object sender, EventArgs e)
{
    if (this.dgvTransactionTable.SelectedRows.Count == 0)
    {
        MessageBox.Show("Please Choose a Row", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    DataGridViewRow row = this.dgvTransactionTable.SelectedRows[0];
    int id = Convert.ToInt32(row.Cells["id"].Value);
    
    // using语句会在代码块结束时自动释放数据库资源,无需手动判断开关状态
    using (SqlConnection con = new SqlConnection(connectionString))
    {
        // 参数化查询避免SQL注入
        const string sql = "SELECT transaction_name, category, trans_date, amount FROM transactions WHERE id = @TransId";
        using (SqlCommand cmd = new SqlCommand(sql, con))
        {
            cmd.Parameters.AddWithValue("@TransId", id);
            con.Open();
            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                if (dr.Read()) 
                {
                    // 按字段名读取值,做对应类型转换
                    string transName = dr["transaction_name"].ToString();
                    string category = dr["category"].ToString();
                    DateTime transDate = Convert.ToDateTime(dr["trans_date"]);
                    decimal amount = Convert.ToDecimal(dr["amount"]);
                    
                    // 通过构造函数传值后打开窗体
                    TransactionView transactionView = new TransactionView(transName, category, transDate, amount);
                    transactionView.Show();
                }
            }
        }
    }
}

注意事项

  • 代码中的数据库字段名、交易金额对应的控件名请根据实际项目命名替换
  • 若cmbTransactionCategory绑定了枚举或数据源,不要直接给Text赋值,需通过SelectedValue匹配对应选项,避免选项选中失效
  • 读取数据时优先使用字段名而非序号索引,降低后续表结构调整引发的错误概率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 22:09:39