0

I want to restore previous series after changing some Yvalues[0] multiple times in the chart. So I have implemented undo operation using memento pattern.

But it's not working and there is no error while running. Below is the originator, memento and caretaker.

public class Originator
{

    private Series _series = new Series();

    public Originator(Series series)
    {
        _series = series;
    }
    public Series OSeries
    {
        get
        {
            return _series;
        }
        set
        {
            _series = value;
        }
    }

    public Memento SaveSeries()
    {
        return new Memento(_series);
    }

    public void RestoreSeries(Memento m)
    {
        this._series = m.MMseries;
    }
 }

public class Memento
{
    private Series _series =new Series();

    public Memento(Originator org)
    {
        this._series = org.OSeries;
    }
    public Memento(Series mseries)
    {
        _series = mseries;
    }

    public Series MMseries
    {
        get
        {
            return _series;
        }
        set
        {
            _series = value;
        }
    }
}
public class Caretaker
{
    //  private static Caretaker _instance;


    //  public Caretaker() { }

    private Memento chartMemento;
    public Memento Memento
    {
        get
        { return chartMemento; }

        set
        {  chartMemento = value; }

    }
}

Created objects in public partial class Form1 : Form

Originator _org;
Caretaker taker = new Caretaker();

While loading the chart from a file, open_file function contains this code:

_org = new Originator(global_series); //For undo/redo operation
while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); }

chart1.Series.Add(global_series);
taker.Memento = _org.SaveSeries();

For Undo_button:

_org.RestoreSeries(taker.Memento);
while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); }
global_series = _org.OSeries;
chart1.Series.Add(global_series);
TaW
  • 53,122
  • 8
  • 69
  • 111
user2587
  • 149
  • 10

2 Answers2

1

Multiple undo operations using Memento Pattern

Code for Caretaker:

public class Caretaker
{

    private Memento chartMemento;
    public Memento Memento
    {
        get
        { return chartMemento; }

        set
        {  chartMemento = value; }

    }
}

Code for Memento:

public class Memento
{
    private Series _series =new Series();

    public Memento(Originator org)
    {
        this._series.Points.Clear();
        foreach (var dp in org.OSeries.Points) this._series.Points.Add(dp.Clone());
    }
    public Memento(Series mseries)
    {
        this._series.Points.Clear();
        foreach (var dp in mseries.Points) this._series.Points.Add(dp.Clone());
    }

    public Series MMseries
    {
        get
        {
            return _series;
        }
        set
        {
            _series = value;
        }
    }
}

Code for Originator

public class Originator{
    private Series _series = new Series();
    public Originator() { }
    public Originator(Series series)
    {
        // _series = series;
        _series.Points.Clear();
        foreach (var dp in series.Points) _series.Points.Add(dp.Clone());
    }
    public Series OSeries
    {
        get
        {
            return _series;
        }
        set
        {
            _series = value;
        }
    }

    public Memento SaveSeries()
    {
        return new Memento(_series);
    }

    public void RestoreSeries(Memento m)
    {
        //this._series = m.MMseries;

        this._series.Points.Clear();
        foreach (var dp in m.MMseries.Points) this._series.Points.Add(dp);
        this._series.ChartType = SeriesChartType.Line;
    }

}

Declare list of objects and its counter in the Form1

 Orginator _org;
 List<Originator> list_org = new List<Originator>();
 List<Caretaker> list_taker = new List<Caretaker>();
 int obj_counter = 0;

Code for Do operations

 list_org.Add(_org = new Originator(global_series));
 Caretaker ct = new Caretaker();
 ct.Memento = list_org[obj_counter++].SaveSeries();
 list_taker.Add(ct);

Code for Undo operations:

  if (obj_counter > 0)
  {
     list_org[--obj_counter].RestoreSeries(list_taker[obj_counter].Memento);
     global_series.Points.Clear();
     foreach (var dp in list_org[obj_counter].OSeries.Points) 
     global_series.Points.Add(dp);
  }
user2587
  • 149
  • 10
0

Series is a reference variable.

Therefore all changes you make will be be to the series and all references you have will point to the same (original) series.

Fancy patterns, useful as they might be can't replace elementary knowledge. To allow undo/redo you need a copy of the data, not of the reference!

Note the Series doesn't have a Clone method.

So you need to do it yourself; in your case this boils down to copying the Points..

But for a more general case you would want to copy other series properties, most notable the ChartType but basically everyting you did to prepare the Series. Maybe create it in a factory pattern..?

But also note the DataPoint does have a Clone method. So you may change your Originator constructor like so:

public Originator(Series series)
{
    //_series = series;
    foreach (var dp in series.Points) _series.Points.Add(dp.Clone());
}

and things will start to work as expected. But you will need to do the restoring like this as well or else you would point to the saved series and the next changes would change it instead of the chart series..:

public void RestoreSeries(Memento m)
{
    // this._series = m.MMseries;
    this._series.Points.Clear();
    foreach (var dp in m.MMseries.Points) this._series.Points.Add(dp);
}

Btw: To clear all series use chart.Series.Clear() !

TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thanks a lot , its working! Although for single undo operation. I'm sure this will give a start up to do multiple undo operations. Once I get solution, I will upload the code. – user2587 Aug 09 '18 at 16:25
  • The usual solution for multiple do/undo operatins is a queue. Or is the pattern supposed to work for multiple undos? In that case I missed a bit.. – TaW Aug 09 '18 at 16:56
  • Yes the pattern should work for multiple undos. Can this happen ? – user2587 Aug 09 '18 at 17:04
  • Ah, ok the Memento makes the same mistake of just copying references.. But I think for multiple undos you need a `List`, see [here](https://en.wikipedia.org/wiki/Memento_pattern) - Also see [this discussion](https://stackoverflow.com/questions/3448943/best-design-pattern-for-undo-feature) – TaW Aug 09 '18 at 17:15
  • I made 'List' and 'List'. Its working for multiple undo operations. The code is given below. – user2587 Aug 10 '18 at 03:46