第五天 -- 《2014-07-21 三层架构》-- 在DataGridView控件上直接修改和Update

一、上午《01、修改dgv控件中下拉列表的添加》--《03、添加了ValueMenber之后列绑定属性的修改》

1、将DataGridView中的列指定为需要的类型。

如下图:创建DataGridViewColumn时需要指定为真正需要的子类型。这样才能更好地编辑行数据。这些类型有:Button、CheckBox、ComboBox、Image、Link、TextBox 

  这些子类型的列,正如其名。与同名的单独控件有类似的属性、功能和事件。比如DataGridViewButtonColumn就像一个Button控件;而DataGridViewComboBoxColumn就像一个ComboBox控件,可以绑定下拉列表的数据源,可以指定项应该显示绑定对象的什么属性,选中值应该对应绑定对象的什么属性。等等。

 

2、指定下拉项的数据源。

如以下代码:

 1 //在DataGridView表格控件绑定数据源之前,先绑定下拉列表列的数据源。如此一来,用户编辑该列时,可以下拉选择可选项。
 2 var  column = this.dgvList.Columns["cname"] as DataGridViewComboBoxColumn;//注意:表格列名 = 数据库列名 = 实体类属性名。推荐这样的命名方式。必须将列显式转为子类型。
 3 if (column != null)
 4 {
 5     column.DisplayMember = "cname"; //显示值。即绑定实体对象的属性名。
 6     column.ValueMember = "cid";//实际值  有更高的优先级,如果同时指定了这两项属性,那么真正的对应字段是ValueMember.以后拿出来进行匹配的就是cid值。与之匹配的也必须是对应类型和意义的字段或者属性名称
 7     column.DataSource = cm.GetAllClassesList(false);//BLL层通过DAL层获取实体对象集合——“班级表”的查询结果集
 8     column.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;//非编辑时,不显示下拉按钮
 9 }
10 
11 this.dgvList.DataSource = pm.GetAllPersonList(false);//DataGridView绑定数据源(BLL层从DAL层获取的实体对象集合)

注意:ValueMember指定属性的数据类型必须与该列的绑定数据源属性的数据类型一致。

  针对上例来说:ValueMember指定的是Classes实体类的CID属性。该DataGridViewComboBoxColumn列绑定的是Person实体类的PCID属性。(这两个属性就是主外键关系,Person表的外键PCID对应Classes表的主键CID)。所以:Classes实体类的CID属性和Person实体类的PCID属性都是int整型。这个必须要一致。

 

3、下拉列异常分析

当弹出下图异常时,要冷静分析,该异常说明了这样几个问题:

(1)从哪个单元格开始没加载,说明哪笔数据绑定到表格控件时出了问题。(红圈处)

(2)“所在班级”列的下拉列表中不存在红圈内的项

(3)观察数据源可知,Person表ID为39的记录其PCID值为64(PCID是外键,指向Classes表的CID),而从Classes班级表获取的结果集中,不存在CID为64的记录。(可能是某些历史原因)

表中数据如下:

 

4、DataGridView其他注意事项

(1)每次绑定DataGridView.DataSource数据源的时候,都会触发SelectionChanged事件。

也就是说如果你订阅了SelectionChanged事件,每次对DataSource赋值后,下一句马上就去执行该事件处理的代码。当这个事件处理方法结束,才会接着执行赋值语句下一行。流程如下图所示:

                            

  因为DataGridView控件的SelectionMode有5个类型,分别代表选中模式(单元格选中、整行选中、整列选中、点单元格只选单元格点行头选中整行、点单元格只选单元格点列头选中整列)详见上右图。所以如果你订阅了SelectionChanged事件,每次对DataSource赋值后,都会进入5次SelectionChanged事件处理方法。

 

(2)手动让单元格进入编辑状态

  允许用户编辑单元格时,默认情况下用户需要先选择行(或单元格),再双击单元格才能开始编辑(我试了试开始编译一个未选中的单元格需要点击3次鼠标左键)。有的人喜欢选中单元格时直接进入编辑状态。可以使用如下代码,手动进入编辑状态。

1 //点击单元格,指定立马进入该单元格的编辑状态
2 private void dgvList_CellClick(object sender, DataGridViewCellEventArgs e)
3 {//点击单元格,指定进入到编辑状态
4     this.dgvList.BeginEdit(true);
5 } 

注意:但是这样做也有不爽的地方,有的人阅读内容的时候喜欢在字里行间点来点去,一不小心修改了内容并换了行。那就直接Update了。

 

二、上午《04、添加切换行和判断是否进入编辑状态的事件》--《07完成直接在dgv控件中进行的修改操作》 --直接在DataGridView的行上修改数据后Update到数据库

1、订阅DataGridView的CellBeginEditSelectionChanged事件,实现行数据修改后Update到数据库的功能。

 1 //下面字段用于标识单元格编辑后,只有在数据被改变才Update数据库。
 2 private bool _isEdited = false;//选中行是否进入过编辑状态
 3 private bool _isFirst = true;//单元格是不是该行第一个进入修改的单元格。显而易见一行可以有多个单元格被编辑,每个单元格被编辑都会进入CellBeginEdit事件处理。
 4 private Person _current;//选中行绑定项
 5 private Person _original = new Person();//编辑前的实体对象(用来在用户选中其他行后,把编辑前和现在绑定的对象数据做对比,只有真正修改了才去Update数据库)
 6 
 7 private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
 8 {//选中单元格进入编辑状态时触发。(主要用来保存编辑前的数据)
 9     _isEdited = true;
10     _current = this.dataGridView1.CurrentRow.DataBoundItem as Person;//这是编辑前。_current就是选中行绑定项
11     if (_isFirst)
12     {//如果本单元格是该行第一个进入编辑的,应该把_current存到_original中,也就是把编辑前对象存好。而编辑后_current的内容会随之改变。
13         _original.PCID = _current.PCID;
14         _original.PCName = _current.PCName;
15         _original.PGender = _current.PGender;
16         _original.PEmail = _current.PEmail;
17         _original.PType = _current.PType;
18         _isFirst = false;
19     }
20 }
21 
22 private void dataGridView1_SelectionChanged(object sender, EventArgs e)
23 {//当用户选中另一行之后,如果刚才编辑的行数据修改了,应该Update数据库。
24     if (_isEdited)//如果上一个选中行被编辑过(进过编辑状态)
25     {
26         if (_original.PCID != _current.PCID || _original.PCName != _current.PCName || _original.PGender != _current.PGender
27             || _original.PType != _current.PType || _original.PEmail != _current.PEmail)
28         {//如果上一个选中行绑定的数据做了编辑修改
29 
30             if (UpdatePerson(_current) == 1)
31             {//Update实体对象到数据库
32                 MessageBox.Show("ok");
33                 _isEdited = false;
34                 this.dataGridView1.DataSource = GetList();
35             }
36         }
37         _isFirst = true;
38         _isEdited = false;
39     }
40 }

注意:每个时间点上,获取的this.dataGridView1.CurrentRow.DataBoundItem绑定项,都是绑定的实时的数据(实体对象)。

也就是说每次改动了绑定项的数据,下次再获取该绑定项,获取的就是每次修改后的实体对象。

 

posted on 2017-09-05 15:48  困兽斗  阅读(3467)  评论(0)    收藏  举报

导航