Tuve este problema también. Lo resolví usando "The Memento Pattern Design". Con este patrón, puede guardar fácilmente una copia de su objeto original y, en selectedIndexChange
(de un control) o en el botón Cancelar, puede restaurar fácilmente la versión anterior de su objeto.
Un ejemplo de uso de este patrón está disponible en How is the Memento Pattern implemented in C#4?
Un ejemplo de código:
Si tenemos un usuario de clase con propiedades Nombre de usuario Contraseña y NombrePersona tenemos que añadir métodos CreateMemento y 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;
}
Entonces, necesitamos un Memento clase que contendrá la "copia" de nuestro objeto de esta manera:
/// <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; }
}
}
y necesitamos una clase que va a generar y contiene nuestro objeto memento:
/// <summary>
/// The 'Caretaker' class
/// </summary>
class Caretaker
{
private Memento _memento;
// Gets or sets memento
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}
Entonces, para poner en práctica esta patrón tenemos que crear una instancia de Caretaker
clase
Caretaker creadorMemento = new Caretaker();
Y crear nuestro objeto de recuerdo cuando se seleccionó un nuevo usuario para editar, por ejemplo en selectedIndexChange
después de que el Usuario Seleccionado se haya inicializado, utilizo el método para el evento RaisPropertyChanged
de esta manera:
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);
}
}
Una explicación para esto, cuando selectedIndexChanged
valor de cambio en el que comprobar si UserSelected
y our memento object
no son nulos significa que nuestro artículo en modo de edición ha cambiado, entonces tenemos que restaurar nuestro objeto con el método SetMemento
. Y si nuestra propiedad UserSelected
cambia y no es nula, "Crearemos nuestro objeto de recuerdo" que usaremos cuando se canceló la edición.
Para terminar, tenemos que utilizar el método SetMemento
en cada método que necesitamos para cancelar la edición, y cuando la edición se ha comprometido como en el SaveCommand podemos establecer nula nuestro objeto recuerdo como esto this.creadorMemento = null
.
IEditableObject crea una gran cantidad de sobrecarga para sus objetos, especialmente si los objetos de su Modelo son una Clase y no una Struct, tendría que volver a escribir sus objetos de modelo para admitirlo. – Agies
@Agies: ¿Por qué el voto a favor? Si IEditableObject es una "gran cantidad de gastos generales" o no, depende completamente de su infraestructura o de cómo quiera implementarla. Es solo una interfaz que WPF entiende. Cómo lo implementa depende de usted. –
+1, sí, quiero implementarlo con IEditableObject, pero tengo un ViewModelBase que expone un Modelo de propiedad de tipo TModel y ato la Vista directamente a las propiedades del modelo expuesto. Ahora, ¿cómo podría seguir usando 'Cancelar edición', también, ahora que conoce mi escenario, diga que mi TModel es una entidad de Dirección. en modo de vista, solo se une a la línea FullAddress y utiliza la plantilla AddressDataTemplate (haciendo un enlace a GMaps), pero quiero que cuando el usuario haga clic en el botón Editar en la AddressView, abra una ChildWindow (SL o cualquier ventana en WPF) para continuar ... –
Shimmy