加载中…
个人资料
ParkerWu
ParkerWu
  • 博客等级:
  • 博客积分:0
  • 博客访问:44,642
  • 关注人气:46
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

在WPF中EFCore与ObservableCollection集合的配合使用

(2020-03-22 12:02:46)
标签:

wpf

ef

core

observablecollection

数据通知

 

          EF CoreObservableCollection集合的配合使用

问题的提出:通过EF Core获取到数据集合,然后填充到ObservableCollection集合对象,方便WPF的数据集控件,譬如DataGrid进行数据绑定,如果数据是只读的,不需要任何额外操作,但用户希望在DataGrid控件中进行数据的添加/编辑/删除后,然后希望一键再保存到数据库中去,传统的做法可通过DataTable实现,但DataTable太复杂,且没有实现集合变更的通知消息,譬如向DataTable中添加行时,可能不能及时刷新到UI,显然使用具有集合通知功能的ObservableCollection对象更具有通用性,但ObservableCollection对象本身并无记录数据变更的功能,因此需要扩展。

    以下代码同时实现了对数据的标新和标记修改功能

1>    添加所有通用数据集需要实现的接口IDataRow

    public interface IDataRow: INotifyPropertyChanged

    {

        ///  < summary >

        /// 是否该行已被修改

        ///  < /summary >

        boolIsModified { get; set; }

        ///  < summary >

        /// 是否为新添加的行

        ///  < /summary >

        bool IsNew { get; set; }

      

}

2>    添加一个实现了IDataRow接口的用于测试的数据对象

下面的代码使用的是DevExpressMVVM框架的ViewModelBase,不过使用任意的实现了INotifyPropertyChanged通知类都可以

    public class DepartmentData : ViewModelBase, IDataRow

    {

        public long ID

        {

            get { return GetValue < long > (); }

            set { SetValue(value); }

        }

        public string Name

        {

            get { return GetValue < string > (); }

            set { SetValue(value); }

        }

        public string Description

        {

            get { return GetValue < string > (); }

            set { SetValue(value); }

        }

        ///  < summary >

        /// 是否已修改

        ///  < /summary >

        [JsonIgnore]

        public bool IsModified

        {

            get { return GetValue < bool > (); }

            set { SetValue(value); }

        }

        ///  < summary >

        /// 是否是新增项

        ///  < /summary >

        [JsonIgnore]

        public bool IsNew

        {

            get { return GetValue < bool > (); }

            set { SetValue(value); }

        }

    }//

   注意:[JsonIgnore]是用于通过Web API访问时标识不需要进行序列化的属性,如果是本地访问,可以删除。

3>    实现ObservableCollectionEx扩展类

        public class ObservableCollectionEx< T>  : ObservableCollection < T >

        where T: IDataRow

    {

        public List < T >  AddedItems;//记录添加的项

        public List < T >  DeletedItems;//记录删除的项

        public List < T >  ModifiedItems;//记录数据修改的项

        #region 构造函数

        public ObservableCollectionEx() : base()

        {

            AddedItems = new List < T > ();

            DeletedItems = new List < T > ();

            ModifiedItems = new List < T > ();

        }

        public ObservableCollectionEx(List < T >  list) : base(list)

        {

            //添加属性通知

            foreach (var item in list)

            {

                ((T)item).PropertyChanged += ObservableCollectionEx_PropertyChanged;

            }

            AddedItems = new List < T > ();

            DeletedItems = new List < T > ();

            ModifiedItems = new List < T > ();

        }

        public ObservableCollectionEx(IEnumerable < T >  collection) : base(collection)

        {

            //添加属性通知

            foreach(var item in collection)

            {

                ((T)item).PropertyChanged += ObservableCollectionEx_PropertyChanged;

            }

            AddedItems = new List < T > ();

            DeletedItems = new List < T > ();

            ModifiedItems = new List < T > ();

        }

        #endregion

        //当有AddRemove命令时会触发

        protected override voidOnCollectionChanged(NotifyCollectionChangedEventArgs e)

        {

            base.OnCollectionChanged(e);

            if (e.NewItems != null)

            {

                foreach (var n in e.NewItems)

                {

                    //添加项都需要修改通知,因为最终保存后就需要使用

                    ((T)n).PropertyChanged -= ObservableCollectionEx_PropertyChanged;

                    ((T)n).PropertyChanged += ObservableCollectionEx_PropertyChanged;

                    if (!SuspendDataChange) //记录数据更改

                    {

                        AddedItems.Add((T)n);

                        ((T)n).IsNew = true;//设置为新项

                    }                  

                }

            }

            if (e.OldItems != null)

            {

                foreach (var m in e.OldItems)

                {

                    //删除修改通知

                    ((T)m).PropertyChanged -= ObservableCollectionEx_PropertyChanged;

                    ((T)m).IsNew = false;//取消设置为新项

                    ((T)m).IsModified = false;

                    if (ModifiedItems.Contains((T)m)) //从修改项中删除

                    {

                        ModifiedItems.Remove((T)m);

                    }

                    if (!SuspendDataChange) //记录数据更改

                    {

                        if(AddedItems.Contains((T)m))

                        {

                            AddedItems.Remove((T)m);

 

                        }

                        else

                        {

                            DeletedItems.Add((T)m);                         

                        }

                    }

                }          

            }

            if (!IsDirty && (AddedItems.Count > 0 || DeletedItems.Count > 0))

            {

                IsDirty = true;

            }

        }

        //数据项发生改变

        private voidObservableCollectionEx_PropertyChanged(object sender, PropertyChangedEventArgs e)

        {

            //只有当项不是添加项时,属性的修改才会被认为是数据修改

            if (!ModifiedItems.Contains((T)sender) && !AddedItems.Contains((T)sender) && !SuspendDataChange)

            {

                ModifiedItems.Add((T)sender);

                ((T)sender).IsModified = true;

                IsDirty = true;

            }

 

        }

 

        ///  < summary >

        /// 清除编辑记录

        ///  < /summary >

        public void ClearEditRecorder()

        {

            //清空标识

            foreach (var item in Items)

            {

                item.IsNew = false;

                item.IsModified = false;

            }

            AddedItems.Clear();

            DeletedItems.Clear();

            ModifiedItems.Clear();

            IsDirty = false;

        }

        ///  < summary >

        /// 清除属性通知

        ///  < /summary >

        public voidClearPropertyNotice()

        {

            foreach (var item in Items)

            {

                item.PropertyChanged -= ObservableCollectionEx_PropertyChanged;

            }

        }

        protected override void ClearItems()

        {           

            base.ClearItems();

            ClearEditRecorder();

        }

        ///  < summary >

        /// 是否记录数据更改

        ///  < /summary >

        public bool SuspendDataChange { get; set; } = false;

        bool_IsDirty;

        ///  < summary >

        /// 数据是否已经修改

        ///  < /summary >

        public bool IsDirty

        {

            get { return _IsDirty; }

            set

            {

                if(value!= _IsDirty)

                {

                    _IsDirty = value;

                    this.OnPropertyChanged(new PropertyChangedEventArgs("IsDirty"));

                }

            }

        }

    }//

 

4>    使用

定义集合对象

publicObservableCollectionEx < DepartmentData >  ItemsSource

{

                get { return GetValue < ObservableCollectionEx <  DepartmentData  >  > (); }

                set { SetValue(value); }

}

//填充集合,responseResult为通过EF Core查询到的DepartmentData数据集

ItemsSource = new ObservableCollectionEx < DepartmentData > (responseResult);

 

然后就可以将ItemsSource集合绑定到DataGridItemsSource属性上,保存按钮的IsEnabled属性绑定到ItemsSource集合的IsDirty属性上,后面就可以对数据源ItemsSource进行各种添加/删除/修改操作,而这又是可以实时反应到UI的,相反的在UI上的删除(通过DataGrid的删除键)或者修改也会立即体现到数据集上。

 

最后点击保存时代码类似如下:

if (ItemsSource.AddedItems.Count  >  0)//添加数据

{

    _Context. Departments.AddRange(ItemsSource.AddedItems);

}

if(ItemsSource.DeletedItems.Count  >  0) //删除数据

{

    _Context. Departments.RemoveRange(ItemsSource. DeletedItems);

}

if(ItemsSource.ModifiedItems.Count  >  0) //修改数据

{

   //远程Web API更新数据时,在此次发送修改的数据

   //本地更新无需考虑,所有数据的修改状态都已被EF Core实时追踪

}

//然后调用保存功能

_context.SaveChanges ();

//最后清除编辑状态

ItemsSource.ClearEditRecorder();

这个数据集的扩展不仅可以用于本地数据库的编辑也可以用于远程WEB访问的形式编辑数据


0

阅读 收藏 喜欢 打印举报/Report
前一篇:机器人的世界
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有