Подтвердить что ты не робот

Как отменить редактирование объекта с помощью MVVM?

Как я могу реализовать отмену редактирования объекта с помощью MVVM.

Например: у меня есть список клиентов. Я выбираю одного клиента щелчком кнопки "Изменить", открывается диалоговое окно (DataContext привязано к CustomerViewModel), и я начинаю редактировать поля клиента. И затем я решил отменить редактирование, но поля клиента уже были изменены, поэтому как я могу вернуть клиента в его предыдущее состояние в MVVM?

4b9b3361

Ответ 1

Проверьте IEditableObject интерфейс. Ваш класс Customer должен реализовать это, и ваши команды могут выполнить BeginEdit/CancelEdit/EndEdit, если это необходимо.

Ответ 2

Один очень простой способ, если ваш объект уже сериализуем, например, если вы используете WCF. Вы можете сериализовать исходный объект во внутреннее поле. Если ваш объект не является сериализуемым, просто используйте AutoMapper, чтобы создать копию вашего объекта с помощью одной строки кода.

Order backup = Mapper.Map<Order, Order>(order);

Когда вы обрабатываете свой CancelCommand, просто вызовите AutoMapper в обратном порядке. Поскольку у ваших свойств уже есть уведомление об изменении, все работает. Возможно, вы могли бы объединить эти методы с IEditableObject, если вам нужно и хотите написать дополнительный код.

Ответ 3

В в этой статье Рауль просто перезагружает объект из БД. Я предполагаю, что это меньше проблем, чем предлагает решение Кент.

    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);
    }

Ответ 4

У меня тоже была эта проблема. Я решил это, используя "Дизайн шаблона Memento". С помощью этого шаблона вы можете легко сохранить копию своего исходного объекта, а в selectedIndexChange (элемента управления) или в кнопке "Отмена" вы можете легко восстановить предыдущую версию своего объекта.

Пример использования этого шаблона доступен в Как используется шаблон Memento в С# 4?

Пример кода:

Если у нас есть класс User со свойствами 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; }
    }
}

И нам нужен класс, который будет генерировать и содержать наш объект mymento:

/// <summary>
/// The 'Caretaker' class
/// </summary>
class Caretaker
{
    private Memento _memento;

    // Gets or sets memento
    public Memento Memento
    {
        set { _memento = value; }
        get { return _memento; }
    }

}

Затем для реализации этого шаблона мы должны создать экземпляр Caretaker class

Caretaker creadorMemento = new Caretaker();

И создайте объект mymento, когда новый пользователь был выбран для редактирования, например, в selectedIndexChange после инициализации SelectedUser, я использую метод для события 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 изменяется и не является нулевым, мы создаем "Объект Memento", который мы будем использовать, когда редактирование было отменено.

Для завершения мы используем метод SetMemento в каждом методе, который нам нужно отменить издание, и когда редактирование выполнено, как в SaveCommand, мы можем установить нулевой объект mymento, как этот this.creadorMemento = null.

Ответ 5

Вы также можете, в своей модели ViewModel копировать состояние модели во внутренние поля, а затем выставлять их, а затем устанавливать их только на модели, когда пользователь действительно совершает изменение.

Проблема может заключаться в том, что проверка "на лету" будет более сложной, если проверка зависит от обновляемого объекта. Если это требование, вы можете создать клон модели для работы, а затем слить клон с помощью фактическая сущность при ее сохранении.

Ответ 6

Вы можете использовать привязку с UpdateSourceTrigger = Explicit. Здесь вы можете найти дополнительную информацию о том, как это можно реализовать.

Ответ 7

На основе Камен Великов ответьте:

Вы можете пометить свои привязки как обновленные вручную, указав

<TextBox Name="yourTextBox" Text="{BindingPath=YourBinding, UpdateSourceTrigger=Explicit}" />

на ваш взгляд (XAML). Затем вы должны записать изменения из своего пользовательского интерфейса в ViewModel, вызвав

yourTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
при нажатии кнопки "Сохранить".

Обратите внимание, что если обновленный источник привязки запускается из чего-либо еще, они все еще отображаются непосредственно в пользовательском интерфейсе.