HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Easly cancellable operations WPF

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cancellablewpfoperationseasly

Problem

Several times we need to be able to revert the data the user is inserting to a previous state (cancel data update). In order to keep DRY and for the sake of separation of concerns I thought about a way of just allowing that.

public class RevertableObject : ViewModelBase //implements INotifyPropertyChanged
    where T:class, ICloneable
{
    public RevertableObject(T initialValue)
    {
        Value = initialValue;
        Value = initialValue.Clone() as T;
    } 

    private T _oldValue;
    private T _currentValue;
    public T Value
    {
        get { return _currentValue; }
        private set
        {
            _oldValue = _currentValue;
            _currentValue = value;
            OnPropertyChanged();
        }
    }

    public void Revert()
    {
        Value = _oldValue;
    }
}


Some drawbacks of this solution are, but are not limited to:

  • Dependency on the interface ICloneable which does not have a way of knowing the cloning algorithm being used (member clone vs deep clone)



  • It only allows one object to be reverted once.



Any insights of better alternatives? Is this code acceptable?

Solution

You could empower IEditableObject. Here is a good article. Approach described will allow your model to do not mix concerns - they use memento design pattern.

UPDATE: I do not feel right by copy-pasting that article, so I would still recommend to have a look at it. Quick test though might look like the following:

1) Download and reference BindingOriented.Adapters project in your WPF application.

2) Create model:

public class Contact
{
    public string Name { get; set; }
}


3) Create view model (I used MvvmLight for RelayCommand):

public class MainViewModel 
{        
    public MainViewModel()
    {
        Contact = new EditableAdapter(new Contact() { Name="Dmitry" });
        OKCommand = new RelayCommand(() => Contact.EndEdit());
        CancelCommand = new RelayCommand(() => Contact.CancelEdit());
    }

    public EditableAdapter Contact { get; }
    public ICommand OKCommand { get; }
    public ICommand CancelCommand { get; }
}


4) Update MainWindow to include:


    
        
    
    
    
    


It works :)

Code Snippets

public class Contact
{
    public string Name { get; set; }
}
public class MainViewModel 
{        
    public MainViewModel()
    {
        Contact = new EditableAdapter<Contact>(new Contact() { Name="Dmitry" });
        OKCommand = new RelayCommand(() => Contact.EndEdit());
        CancelCommand = new RelayCommand(() => Contact.CancelEdit());
    }

    public EditableAdapter<Contact> Contact { get; }
    public ICommand OKCommand { get; }
    public ICommand CancelCommand { get; }
}
<StackPanel>
    <StackPanel.DataContext>
        <vm:MainViewModel/>
    </StackPanel.DataContext>
    <TextBox Text="{Binding Contact.Name}"/>
    <Button Content="OK" Command="{Binding OKCommand}"/>
    <Button Content="Cancel" Command="{Binding CancelCommand}"/>
</StackPanel>

Context

StackExchange Code Review Q#118322, answer score: 4

Revisions (0)

No revisions yet.