在WPF中EFCore与ObservableCollection集合的配合使用
2020-03-22 12:02阅读:
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访问的形式编辑数据