一、描述
习惯了BS开发,今天对数据DataTable的DataGridView进行增删改查。遇到一下空白行的问题,记录一下。
二、操作
dg1.AutoGenerateColumns = false;//不自动显示数据库中未绑定的列
dg1.DataSource = dt;
绑数据、开编辑、设定列;
三、操作
private void dg1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridViewRow Row = dg1.Rows[e.RowIndex];//操作行
string dataName = dg1.Columns[e.ColumnIndex].DataPropertyName;//列数据名
string id = Row.Cells[1].Value.ToString().Trim();//数据唯一标识
//记录改动
DataRow _row = dt.AsEnumerable().Where(p => p["id"].ToString() == id).FirstOrDefault();
if (_row==null)//新增行
{
_row = dt.NewRow();
dt.Rows.Add(_row);//加行
//临时ID
int rowcount = dt.Rows.Count;
string _id = $"-{rowcount}";
_row["id"] = _id;
}
_row[dataName] = e.FormattedValue.ToString().Trim();//当前单元格值
}
运行效果
录入11,失去焦点后执行CellValidating,
多了两行空白,愁
PS:我想会不会是dt更新 也触发了本函数,
函数头加个lock,函数尾释放,防执行中被触发,失败!
四、改动1
刷新dt之前禁用行自增AllowUserToAddRows,完事再启用
private void dg1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridViewRow Row = dg1.Rows[e.RowIndex];//操作行
string dataName = dg1.Columns[e.ColumnIndex].DataPropertyName;//列数据名
string id = Row.Cells[1].Value.ToString().Trim();//数据唯一标识
//记录改动
DataRow _row = dt.AsEnumerable().Where(p => p["id"].ToString() == id).FirstOrDefault();
dg1.AllowUserToAddRows = false; //--关
if (_row==null)//新增行
{
_row = dt.NewRow();
dt.Rows.Add(_row);//加行
//临时ID
int rowcount = dt.Rows.Count;
string _id = $"-{rowcount}";
_row["id"] = _id;
}
_row[dataName] = e.FormattedValue.ToString().Trim();//当前单元格值
dg1.AllowUserToAddRows = true;//--开
}
运行效果:
录入11,多了一行,应该是CellValidating所在的ROW无法释放。dt.Rows.Add 数据刷新 又触发了Gridview行编辑的提交。
五、改动2
加一个DataTable做数据缓存。以作后期提交。将页面、数据分开
dt2 = dt.Copy();//定义一个缓存区
---
private void dg1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridViewRow Row = dg1.Rows[e.RowIndex];//操作行
string dataName = dg1.Columns[e.ColumnIndex].DataPropertyName;//列数据名
string id = Row.Cells[1].Value.ToString().Trim();//数据唯一标识
//记录改动
DataRow _row = dt2.AsEnumerable().Where(p => p["id"].ToString() == id).FirstOrDefault();
dg1.AllowUserToAddRows = false; //--关
if (_row==null)//新增行
{
_row = dt2.NewRow();
dt2.Rows.Add(_row);//加行
//临时ID
int rowcount = dt.Rows.Count;
string _id = $"-{rowcount}";
_row["id"] = _id;
Row.Cells[0].Value = _id;//这句的加上了
}
_row[dataName] = e.FormattedValue.ToString().Trim();//当前单元格值
dg1.AllowUserToAddRows = true;//--开
}
运行成功
这次对了,
因为编辑和数据的暂时性差异(Grid会新增行,换行后,整行提交到数据。这期间这条在数据中不存在)
六、问题背后的思考
1、Gridview 绑定数据源,增删查改都很灵活,用DataTable就麻烦一些,很多自带的功能无法实现,比如当前行添加撤销(监听占用当前行)
2、Gridview 是行提交。而DataTable必须列提交。所以注定了数据上暂时的差异。
Grid是缓存一行,失去焦点提交到数据源或DataTable,
DataTable是即时的,行第一格录入不建DataRow,第二格录入就没操作行对象。
而dt.Rows.add后的数据刷新(第1行),会造成Grid新行中断编辑、提交数据(第2行),就会多一行。
3、AllowUserToAddRows是grid 新增行功能,底部会多一行空白,dt.Rows.add如上所说会加两行新增,所以就会有3行新增,这是在CellValidating监听之外的,无法避免。
4、既然grid和dt只能单方面数据同步,所以最终我使用第2个dt作为数据保存副本,之后从逻辑上去避免作业中dt和dt2的最终差异,并使用dt2作为提交到数据库的改动依据。
七、后记
今天偶然用了另外一种思路,成功规避了空白行的生成。
提前在datatable内加入空行,使grid被动加行。避免grid单方面加行后、到行提交前的与datatable的差异。
private void dg1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.RowIndex >= 0)
{
int row = e.RowIndex;
int column = e.ColumnIndex;
if (column < 0) column = 0;
//无值,添加空行
if (dg1.Rows[row].Cells[1].Value == null)
{
DataRow dr = dt.NewRow();
int rowcount = dt.Rows.Count + 1;
string _id = $"-{rowcount}";
//行赋值
dr["name"] = "";
dr["id"] = _id;
dr["model"] = "";
dr["brand"] = "";
dr["salepc"] = 0;
dr["counts"] = "1";
dt.Rows.Add(dr);
}
dg1.ClearSelection();
//右键菜单
//if (e.Button == MouseButtons.Right)
// {
//dg1.CurrentCell = dg1.Rows[row].Cells[column];//更改当前行-焦点变更
//this.cttMenu_dg1.Show(Control.MousePosition);//菜单加到右键 这里做移除右键菜单的ContentStripMenu
// }
}
}