EF Core与ObservableCollection集合的配合使用
问题的提出:通过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接口的用于测试的数据对象
下面的代码使用的是DevExpress的MVVM框架的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
//当有Add和Remove命令时会触发
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集合绑定到DataGrid的ItemsSource属性上,保存按钮的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访问的形式编辑数据
加载中,请稍候......