继续聊WPF DataGrid的问题。
如果我修改了里面一行的内容,如何确定是那一行被修改了,如何对应到相应的数据实体,然后点击保存的时候,就把这些修改过的数据实体保存到数据库呢?
最笨的办法就是,当你保存的时候,把所有的内容都保存一遍,这在数据量小的时候确实也没啥问题,但是数据量大的时候呢?难道都全部保存一遍?这太妈的不靠谱了。
网上找了找资料,大概有以下三种方案:
1、RowEditting事件。
1)在DataGrid中找到RowEditting,双击跑到代码。
2)重新建立两个List,listDepartmentNew用于保存新增的实体(例如 Deparment),listDepartmentEdit用于保存编辑过的实体。
3)保存的时候,在两个List找到数据实体,然后就是该新增的更新,该修改的修改。
private void gridDept_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) { Department dept = (Department)e.Row.Item; foreach(var dep in listDepartmentNew) { if (dep.UID==dept.UID) { return; } } listDepartmentEdit.Add(dept); } private void btnDepartmentSave_Click(object sender, RoutedEventArgs e) { foreach( var dep in listDepartmentNew) { DB.Departments.ExecInsert(dep); } listDepartmentNew.Clear(); foreach( var dep in listDepartmentEdit) { DB.Departments.ExecUpdate(dep); } listDepartmentEdit.Clear(); }
2、PropertyChanged
上面说的第一种方法是不是贼笨了?确实是的,一方面代码多而杂,另外一方面,也不符合我们数据驱动UI的思想,那怎么办?
重新回到“数据驱动UI”这点上来,不就是编辑过了么,编辑的同时,DataGrid就会更新实体的属性,如果我们的实体(类)是实现了 INotifyPropertyChanged这个接口的话,那么就会有PropertyChanged事件响应了。
因此我们又有一种思路:
1)在实体类实现PropertyChanged接口,同时增加一个属性叫做 public bool IsEdited。然后在PropertyChanged事件中让IsEdited=true。
2)这样子在保存的时候,我们可以做一个循环,让IsEdited==True的实体才更新。
3)当然,在数据库取出数据映射成实体的时候,由于会对实体进行赋值,因此IsEdited就会被设置成True,那么你在绑定至DataGrid之前应该将将其设置成False,这是个比较麻烦的地方。
public class ModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public bool IsEdited; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { IsEdited=True; handler(this, new PropertyChangedEventArgs(propertyName)); } } }
3、IEditableObject
上面的方法倒是确实符合数据驱动UI的思路,但是也是由弊端的,比如到底是因为DataGrid改变了数据,还是其它修改改动了数据呢,就区分不清楚,如果微软要更新这个东西,更新反射机制的话,恐怕要加个参数,即是谁Set的,这个比较重要。
此外如此频繁的引入PropertyChange事件,将会导致一个问题,如果这个实体类在其它地方应用,批量更新的话,由于响应的事件多了,性能就下降了!
那么,第三个方法是什么呢?
就是微软官方说的IEditableObject接口,在官方的说明中,微软是要求在DataGrid中的数据源是要实现这个接口的,这个接口有什么用呢?
实现了三个函数BeginEdit CancelEdit EndEdit,换成话说就是开始编辑、取消编辑、结束编辑。
也就是说DataGrid在编辑的时候,分别会调用实体的这三个函数!
再简单来说,DataGrid编辑的时候,会告诉实体,我要开始编辑、取消编辑、结束编辑了,你有什么要做的没有?
那么就有另外一种思路:
1)我们的实体实现IEditableObject,在IEditableObject.EndEdit()函数中,我们将IsEdited设为True。
2)保存的时候看看IsEdited为True的实体,你就更新一下就好了!
public class ModelBase : INotifyPropertyChanged,IEditableObject { public event PropertyChangedEventHandler PropertyChanged; public bool IsEdited; public bool IsAdded = false;//用于记录是否是新增的实体 protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } void IEditableObject.BeginEdit() { //将当前数据的状态,属性进行临时的保存一下 } void IEditableObject.CancelEdit() { // 抛弃在BeginEdit()中保存的临时原始状态! } void IEditableObject.EndEdit() { if (!this.IsEdited) { this.IsEdited = true; } } private void btnRolePowerSave_Click(object sender, RoutedEventArgs e) { foreach (var RP in listRolePowers) { if (RP.IsAdded == true) { DB.Insert(RP); RP.IsAdded = false; } if (RP.IsEdited==true) { DB.Update(RP); RP.IsAdded = false; } } }
好了,上面的代码又优雅,又简洁了,性能也不错,但是你以为就是最好的么?非也,它也存在问题:
1、它不是数据驱动UI思想了,又变成UI驱动数据了,但是这本身没有什么问题,关键是如果微软能够将这一层面的东西做好,也是可以的,用起来会更加灵活。
2、如果你的DataGrid的模板是自己写的话,恭喜你中奖了,因为,自己写的比如CheckBox模板是没有办法通知DataGrid我已经对它编辑了,因此DataGrid就不会调用IEditableObject接口的函数,也就是说实体不知道它被更新了!
当然,这可能也不是没有办法的,因为我还在研究,估计也有办法,就会麻烦一点了,反过来的看的话,反而第二种方法也有它的好处,管你编辑不编辑,只要更新了就是被编辑了。
今天到此为止,下次说说我遇到DataGrid的头疼问题!
如无特别说明,本博客文章皆为原创。转载请说明,来自吵吵博客。
原文链接:http://chaochaoblog.com/archives/3216
吵吵微信朋友圈,请付款实名加入:
数据就是用代码保存的