【问题标题】:Undo operation for series in chart图表中序列的撤消操作
【发布时间】:2019-01-16 17:47:24
【问题描述】:

我想在图表中多次更改 Yvalues[0] 后恢复之前的系列。所以我使用备忘录模式实现了撤消操作。

但它不工作并且运行时没有错误。下面是创始人、纪念品和看守人。

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

    }
}

在公共部分类 Form1 中创建的对象:Form

Originator _org;
Caretaker taker = new Caretaker();

从文件加载图表时,open_file 函数包含以下代码:

_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();

对于撤消按钮:

_org.RestoreSeries(taker.Memento);
while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); }
global_series = _org.OSeries;
chart1.Series.Add(global_series);

【问题讨论】:

    标签: c# winforms design-patterns mschart


    【解决方案1】:

    使用备忘录模式的多个撤消操作

    看守者代码:

    public class Caretaker
    {
    
        private Memento chartMemento;
        public Memento Memento
        {
            get
            { return chartMemento; }
    
            set
            {  chartMemento = value; }
    
        }
    }
    

    纪念品代码:

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

    发起人代码

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

    }

    在Form1中声明对象列表及其计数器

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

    执行操作的代码

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

    撤消操作的代码:

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

    【讨论】:

    • 如果此代码需要任何改进。请告诉我们。
    • @TaW 非常感谢您的建议。这些真的节省了我的时间。
    【解决方案2】:

    Series 是一个引用变量。

    因此,您所做的所有更改都将针对该系列,并且您拥有的所有参考都将指向同一(原始)系列。

    花哨的模式,虽然它们可能有用,但不能代替基本知识。要允许撤消/重做,您需要数据副本,而不是参考

    注意Series 没有Clone 方法。

    所以你需要自己做;在您的情况下,这归结为复制积分..

    但是对于更一般的情况,您可能想要复制其他系列属性,最值得注意的是ChartType,但基本上您为准备Series 所做的一切。也许以工厂模式创建它..?

    但是还要注意DataPoint 确实有一个Clone 方法。所以你可以像这样改变你的Originator构造函数:

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

    一切都会按预期开始。但是您也需要像这样进行恢复,否则您将指向已保存的系列,接下来的更改将更改它而不是图表系列..:

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

    顺便说一句:要清除所有系列,请使用chart.Series.Clear()

    【讨论】:

    • 非常感谢,它的工作!虽然对于单个撤消操作。我确信这将启动执行多个撤消操作。一旦我得到解决方案,我将上传代码。
    • 多个执行/撤消操作的通常解决方案是队列。还是该模式应该适用于多个撤消?在那种情况下,我错过了一点..
    • 是的,该模式应该适用于多次撤消。这会发生吗?
    • 啊,好吧,Memento 也犯了同样的错误,只是复制引用。但我认为对于多次撤消,您需要一个 List&lt;Originator.Memento&gt;,请参阅 here - 另请参阅 this discussion
    • 我制作了“List”和“List”。它适用于多个撤消操作。代码如下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多