如何使用MVVM实现取消编辑对象。
例如:我有一个客户列表。我选择一个客户,单击“编辑”按钮,打开一个对话框窗口(DataContext绑定到CustomerViewModel),然后我开始编辑客户的字段。然后我决定取消编辑,但客户的字段已经更改,那么如何将客户返回到MVVM中的先前状态?
答案 0 :(得分:12)
查看IEditableObject
界面。您的Customer
类应该实现这一点,并且您的命令可以根据需要执行BeginEdit
/ CancelEdit
/ EndEdit
。
答案 1 :(得分:3)
在this article中,Raul只是从数据库重新加载对象。我想这比肯特提出的解决方案要少。
internal void Cancel(CustomerWorkspaceViewModel cvm)
{
Mainardi.Model.ObjectMapping.Individual dc = cvm.DataContext
as Mainardi.Model.ObjectMapping.Individual;
int index = 0;
if (dc.ContactID > 0 && dc.CustomerID > 0)
{
index = _customerCollectionViewModel.List.IndexOf(dc);
_customerCollectionViewModel.List[index] =
_customerBAL.GetCustomerById(dc.CustomerID);
}
Collection.Remove(cvm);
}
答案 2 :(得分:3)
一种非常简单的方法,如果您的对象已经可序列化,例如您使用的是WCF。您可以将原始对象序列化为内部字段。如果您的对象不可序列化,那么只需使用AutoMapper使用一行代码创建对象的副本。
Order backup = Mapper.Map<Order, Order>(order);
当您处理CancelCommand时,只需反向调用AutoMapper。由于您的属性已经有更改通知,因此一切正常。如果您需要并且想要编写额外的代码,可以将这些技术与IEditableObject结合使用。
答案 3 :(得分:2)
您可以使用UpdateSourceTrigger = Explicit绑定。 Here您可以找到有关如何实施此信息的更多信息。
答案 4 :(得分:1)
我也有这个问题。我用“Memento Pattern Design”解决了这个问题。使用此模式,您可以轻松保存原始对象的副本,并且在selectedIndexChange
(控件的)或“取消”按钮中,您可以轻松恢复对象的先前版本。
How is the Memento Pattern implemented in C#4?
提供了使用此模式的示例代码示例:
如果我们有一个具有UserName Password和NombrePersona属性的用户,我们需要添加方法CreateMemento和SetMemento:
public class Usuario : INotifyPropertyChanged
{
#region "Implementación InotifyPropertyChanged"
internal void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private String _UserName = "Capture su UserName";
public String UserName
{
get { return _UserName; }
set { _UserName = value; RaisePropertyChanged("UserName"); }
}
private String _Password = "Capture su contraseña";
public String Password
{
get { return _Password; }
set { _Password = value; RaisePropertyChanged("Password"); }
}
private String _NombrePersona = "Capture su nombre";
public String NombrePersona
{
get { return _NombrePersona; }
set { _NombrePersona = value; RaisePropertyChanged("NombrePersona"); }
}
// Creates memento
public Memento CreateMemento()
{
return (new Memento(this));
}
// Restores original state
public void SetMemento(Memento memento)
{
this.UserName memento.State.UserName ;
this.Password = memento.State.Password ;
this.NombrePersona = memento.State.NombrePersona;
}
然后,我们需要一个Memento类,它将包含我们对象的“副本”,如下所示:
/// <summary>
/// The 'Memento' class
/// </summary>
public class Memento
{
//private Usuario _UsuarioMemento;
private Usuario UsuarioMemento { get; set; }
// Constructor
public Memento(Usuario state)
{
this.UsuarioMemento = new Usuario();
this.State.UserName = state.UserName ;
this.State.Password = state.Password ;
this.State.NombrePersona = state.NombrePersona ;
}
// Gets or sets state
public Usuario State
{
get { return UsuarioMemento; }
}
}
我们需要一个能够生成并包含memento对象的类:
/// <summary>
/// The 'Caretaker' class
/// </summary>
class Caretaker
{
private Memento _memento;
// Gets or sets memento
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}
然后为了实现这个模式,我们必须创建一个Caretaker
类
Caretaker creadorMemento = new Caretaker();
在选择新用户进行编辑时创建我们的memento对象,例如在SelectedUser初始化后的selectedIndexChange
中,我使用事件RaisPropertyChanged
的方法,如下所示:
internal void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
if (prop == "RowIndexSelected") // This is my property assigned to SelectedIndex property of my DataGrid
{
if ((this.UserSelected != null) && (creadorMemento .Memento != null))
{
this.UserSelected.SetMemento(creadorMemento .Memento);
}
}
if (prop == "UserSelected") // Property UserSelected changed and if not is null we create the Memento Object
{
if (this.UserSelected != null)
creadorMemento .Memento = new Memento(this.UserSelected);
}
}
对此进行说明,当selectedIndexChanged
更改值时,我们检查UserSelected
和our memento object
是否为空意味着我们在编辑模式下的实际项目已更改,那么我们必须还原我们的对象使用方法SetMemento
。
如果我们的UserSelected
属性发生更改且不为null,我们将“创建我们的Memento对象”,我们将在取消编辑时使用该对象。
为了完成,我们在取消版本所需的每个方法中都使用了SetMemento
方法,当编辑提交时,就像在SaveCommand中一样,我们可以设置null我们的memento对象,如{{1} }。
答案 5 :(得分:0)
您还可以在ViewModel中将模型的状态复制到内部字段,然后在用户实际提交更改时公开它们,然后仅在模型上设置它们。
问题可能是,如果验证依赖于正在更新的实体,那么即时验证将更加麻烦 - 如果这是一个要求,您可以创建要处理的模型的克隆,然后将克隆与保存时的实际实体。
答案 6 :(得分:0)
您可以通过定义
将绑定标记为手动更新 <TextBox Name="yourTextBox" Text="{BindingPath=YourBinding, UpdateSourceTrigger=Explicit}" />
在您的视图中(XAML)。然后,您必须通过调用
在ViewModel中从UI编写更改 yourTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
单击“保存”时。
请注意,如果更新了从其他任何内容触发的绑定源,它们仍会直接显示在UI中。