IGoUndoableEdit

I have a list of objects (master data), and I want to integrate the data handling (new, edit, delete) into Go’s undo/edo management. Therefore, I think I have to implement IGoUndoableEdit and maybe I have to override GoUndoManager. Unfortunately, there is no example code available. Can anybody help?

Do you want your data to be part of a GoDocument? If so, you don’t need to implement IGoUndoableEdit, because you can just use the implementation that GoChangedEventArgs provides. You don’t need to override any GoUndoManager methods either. But you do need to override GoDocument.ChangeValue.

First, your data class. Your property setter needs to call GoDocument.RaiseChanged. Somehow you need access to the GoDocument from your data. This need not be a field in your data, but that’s how I implemented it in this example.

[code] public class Data {
public Data(GoDocument doc) { myDocument = doc; }

public GoDocument Document {
  get { return myDocument; }
  set { myDocument = value; }
}

public float Prop {
  get { return myProp; }
  set {
    float old = myProp;
    if (old != value) {
      myProp = value;
      this.Document.RaiseChanged(ChangedProp, 0, this, 0, null, GoObject.MakeRect(old), 0, null, GoObject.MakeRect(value));
    }
  }
}
private float myProp;
private GoDocument myDocument;

public const int ChangedProp = GoDocument.LastHint + 51;

}[/code]

Second, the custom document class, which just needs an override of ChangeValue to handle the Hints that you define, like Data.ChangedProp.

[code] [Serializable]
public class SpecialDocument : GoDocument {
public SpecialDocument() {
this.UndoManager = new GoUndoManager();
}

public override void ChangeValue(GoChangedEventArgs e, bool undo) {
  if (e.Hint == Data.ChangedProp) {
    Data d = (Data)e.Object;
    d.Prop = e.GetFloat(undo);
    return;
  }
  base.ChangeValue(e, undo);
}

}[/code]

Finally some tests:

SpecialDocument doc = new SpecialDocument(); Data data = new Data(doc); doc.StartTransaction(); data.Prop = 2; data.Prop = 3; doc.FinishTransaction("changed prop to 3"); System.Diagnostics.Trace.Assert(data.Prop == 3); doc.StartTransaction(); data.Prop = 5; doc.FinishTransaction("changed prop to 5"); System.Diagnostics.Trace.Assert(data.Prop == 5); System.Diagnostics.Trace.Assert(doc.CanUndo()); System.Diagnostics.Trace.Assert(!doc.CanRedo()); doc.Undo(); System.Diagnostics.Trace.Assert(data.Prop == 3); System.Diagnostics.Trace.Assert(doc.CanUndo()); System.Diagnostics.Trace.Assert(doc.CanRedo()); doc.Undo(); System.Diagnostics.Trace.Assert(data.Prop == 0); System.Diagnostics.Trace.Assert(!doc.CanUndo()); System.Diagnostics.Trace.Assert(doc.CanRedo()); doc.Redo(); System.Diagnostics.Trace.Assert(data.Prop == 3); System.Diagnostics.Trace.Assert(doc.CanUndo()); System.Diagnostics.Trace.Assert(doc.CanRedo()); doc.Redo(); System.Diagnostics.Trace.Assert(data.Prop == 5); System.Diagnostics.Trace.Assert(doc.CanUndo()); System.Diagnostics.Trace.Assert(!doc.CanRedo());

Of course, handling different types of properties is exactly the same as when dealing with different types of properties on GoDocument or GoObject. For integer properties, in the property setter, and in the ChangeValue method:

    this.Document.RaiseChanged(ChangedProp, 0, this, old, null, GoObject.NullRect, value, null, GoObject.NullRect);
    d.Prop = e.GetInt(undo);

For reference properties:

    this.Document.RaiseChanged(ChangedProp, 0, this, 0, old, GoObject.NullRect, 0, value, GoObject.NullRect);
    d.Prop = e.GetValue(undo);

Property types that are SizeF, PointF, and RectangleF are like the float case, above. Other value types, including boolean, are handled like reference types. Furthermore, you can use multiple GoChangedEventArgs properties simultaneously. For example, you can use both the integer and the object properties to remember modifications to an array, using the integer property as the index and the object as the value at that index.

Thanks, it works. But undo/redo cannot handle the construction and destruction of Data objects. So, I have added two additional constants DataNew and DataDestroy. In the constructor of the Data class document.RaiseChanged is called with DataNew, in the remove method of the manager class document.raiseChenged with DataDestroy. Special methods in the manager class handle undo/redo for these cases. They are called by the ChangeValue method.