吵吵   2015-02-14  阅读:1,312

继续聊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的头疼问题!

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

一条回应:“WPF DataGrid如何保存编辑或修改过的内容”

  1. 沉鱼落雁随笔说道:

    数据就是用代码保存的

发表评论

电子邮件地址不会被公开。 必填项已用*标注