使用WPF数据绑定时实现事务性编辑(提交/恢复)的好方法

使用WPF数据绑定时实现事务性编辑(提交/恢复)的好方法,wpf,data-binding,transactions,Wpf,Data Binding,Transactions,我有一个相当标准的要求-我需要能够打开一个对话框,用户可以在其中更改数据绑定字段中的值,然后选择单击“确定”或“取消”,单击“取消”将恢复更改 我已经看过了IEditableCollectionView、IEditableObject和BindingGroups,但它们似乎都是用来一次编辑一个项目的。我的程序在列表中提供一组对象,用户从列表中选择一个项目,并使用SelectedItem-boundTextBoxes对其进行编辑。这意味着可以编辑任意数量的项目,包括从列表中添加和删除项目,如果他按

我有一个相当标准的要求-我需要能够打开一个对话框,用户可以在其中更改数据绑定字段中的值,然后选择单击“确定”或“取消”,单击“取消”将恢复更改

我已经看过了
IEditableCollectionView
IEditableObject
BindingGroup
s,但它们似乎都是用来一次编辑一个项目的。我的程序在列表中提供一组对象,用户从列表中选择一个项目,并使用
SelectedItem
-bound
TextBox
es对其进行编辑。这意味着可以编辑任意数量的项目,包括从列表中添加和删除项目,如果他按取消,则需要还原所有这些更改

起初,我只是简单地通过深度复制(序列化)进行对象备份,然后在取消时恢复它们,但现在对象必须包含对其他共享对象的引用,这使得这种方法有问题

在不来回手动复制对象和/或值的情况下,实现这种场景的最佳方法是什么?

在这种情况下,类将完美地工作。它可以保存更改、返回(一步一步)或还原所有更改和许多其他功能。 DataTable类有一个嵌套的特性,可以很好地与XML配合使用


如果您愿意保存在数据库中,请查看

最好的方法不是:


如果需要这些项目,请从数据库或任何数据存储中获取它们的新副本,允许用户进行更改,如果他们按“取消”,则放弃更改。如果他们按save,则将数据保存到存储器中,然后刷新现有屏幕或其他任何内容。

仔细考虑后,我得出结论,至少对于小规模实现而言,最好的方法是编写“按值深度拷贝”方法,该方法复制对象字段和属性的值,而不替换对象本身(以便即使恢复数据,对已编辑对象的任何引用也保持不变)

为此,我编写了以下扩展方法:

public static void CopyDataTo(此对象源,对象目标){
//递归到列表中
如果(源为IList){
var a=0;
foreach(IList源中的var项){
如果(a>=((IList)目标).Count){
var type=item.GetType();
var assembly=assembly.GetAssembly(类型);
var newItem=assembly.CreateInstance(type.FullName);
((IList)目标)。添加(新项);
}
项目.CopyDataTo((IList)目标)[a];
a++;
}
while(a<((IList)目标)。计数){
(IList)目标;
}
}
//在字段上复制
foreach(source.GetType().GetFields()中的变量字段)
field.SetValue(目标,field.GetValue(源));
//复制属性
foreach(source.GetType().GetProperties()中的var属性。其中(
property=>property.CanWrite&&!property.GetMethod.GetParameters().Any())
{
SetValue(目标、属性、GetValue(源));
}
}
它不是万能的:它只适用于相同类型的对象,列表项必须有一个无参数构造函数,并且没有办法控制递归深度。此外,我还没有机会在任何长期或更复杂的场景中进行测试,但到目前为止,它做了它应该做的事情(在对象之间复制值),可以用于简单的备份/恢复场景:

var backup=variableToEdit()的新类型;
data.CopyDataTo(备份);
var clickedOK=RunDataEditor(数据);
如果(!单击确定)
backup.CopyDataTo(数据);

我正在使用DataContractSerializer将对象图存储在XML文件中。我一开始是这样做的,每次对任何对象上的任何属性进行任何编辑时都会重新加载整个图形,但一旦数据增长,它可能会很快变得非常昂贵。所以我想避免它,只在启动时读取存储(并且只在按下OK时保存)。感谢指针,我查看了
DataTable
s,可能会在将来更大的项目中使用它们。不过,对于这个应用程序来说,这是一个过分的技巧,我仍然在学习C#和WPF,所以我想让它简洁明了。