如何通过DataReader将选中字段数据添加到DataGridView?解决行归属报错
问题分析与解决方案
嘿,我来帮你排查这个问题!你遇到的Row provided already belongs to a DataGridView control错误,根源其实很简单:你在循环外只创建了一个DataGridViewRow实例,第一次插入后它已经属于DataGridView了,第二次循环再插入同一个对象就触发了控件的限制。
具体问题点
看你的代码,DataGridViewRow row = (DataGridViewRow)obj.Rows[0].Clone();这行是在while (dr.Read())循环外面定义的,意味着整个循环里你一直在复用同一个row对象。当你第一次调用obj.Rows.Insert(ri,row)后,这个row就被绑定到了DataGridView上,第二次再尝试插入它,控件自然会报错——一个行实例不能同时属于同一个DataGridView多次。
修改后的代码
把row的创建移到while循环内部,每次循环都克隆一个新的行对象,这样每次插入的都是独立的行,就不会有重复归属的问题了。另外我还优化了一些冗余代码和潜在的小问题:
public static void fillGrd(ref DataGridView obj, string tbl, string fld = "*", string cond = "") { try { // 先清空原有数据 obj.Rows.Clear(); obj.Columns.Clear(); // 如果DataGridView已预先定义列,可删除此行 // 拼接SQL语句 cond = string.IsNullOrEmpty(cond) ? "" : " where " + cond; string qry = $"select {fld} from {tbl}{cond}"; cmd.CommandText = qry; using (var dr = cmd.ExecuteReader()) // 使用using自动释放DataReader资源 { if (dr.HasRows) { // 动态生成DataGridView列(按需保留) for (int i = 0; i < dr.FieldCount; i++) { obj.Columns.Add(dr.GetName(i), dr.GetName(i)); } int ri = 0; while (dr.Read()) { // 每次循环都克隆新的行 DataGridViewRow row = (DataGridViewRow)obj.Rows[0].Clone(); for (int i = 0; i < dr.FieldCount; i++) { // 用GetValue避免类型转换问题,兼容非字符串字段 row.Cells[i].Value = dr.GetValue(i)?.ToString() ?? ""; } obj.Rows.Insert(ri, row); ri++; } } } } catch (Exception ex) { MessageBox.Show($"Error occured! {ex.Message}"); } }
额外注意事项
- 用
using包裹DataReader,能自动关闭并释放资源,避免数据库连接泄漏; - 原来的
dr.FieldCount -1会漏掉最后一列,改成dr.FieldCount才能读取所有字段; - 用
dr.GetValue(i)?.ToString()替代dr.GetString(i),避免非字符串类型字段触发转换错误; - 如果你的DataGridView已经预先配置好列,可以删除动态生成列的代码块。
内容的提问来源于stack exchange,提问作者Deepal Nanayakkara
相关产品推荐
相关产品推荐

