To implement Undo, the simplest way is to use a MemoryStream object in your WaveDisplayForm (MDI Child) and simply serialize the Wave (which should be marked as [Serializable] to the stream and hold on to the stream object.
private MemoryStream _undoStream = new MemoryStream();
private bool _canUndo = false;
public void SaveForUndo()
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(_undoStream, wave);
_undoStream.Flush();
// This rewinds the stream so that when it is used for deserialization, it's ready to use,
// otherwise, the deserialization will start deserializing from the end of the stream and would fail.
_undoStream.Position = 0;
_canUndo = true;
}
public void Undo()
{
BinaryFormatter bf = new BinaryFormatter();
_wave = (Wave)bf.Deserialize(_undoStream);
_canUndo = false;
// increment the modified counter on the wave (However you implemented this), i did it using the following method on the Wave object
_wave.DecrementModificationCounter(); // simply does a _modifiedCounter--
Invalidate();
}
private MemoryStream _undoStream = new MemoryStream();
private bool _canUndo = false;
public void SaveForUndo()
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(_undoStream, wave);
_undoStream.Flush();
// This rewinds the stream so that when it is used for deserialization, it's ready to use,
// otherwise, the deserialization will start deserializing from the end of the stream and would fail.
_undoStream.Position = 0;
_canUndo = true;
}
public void Undo()
{
BinaryFormatter bf = new BinaryFormatter();
_wave = (Wave)bf.Deserialize(_undoStream);
_canUndo = false;
// increment the modified counter on the wave (However you implemented this), i did it using the following method on the Wave object
_wave.DecrementModificationCounter(); // simply does a _modifiedCounter--
Invalidate();
}
I thought the simpliest way to make
ReplyDeleteprivate Wave _waveUndo = null;
in WaveDisplayForm. If we need to make many Undo we can make a List (stack).
Why we need these things with stream?
Seems I don't understand something...
That would be fine too. The only reason I recommend to use a MemoryStream in general is to not have to copy each element within the Wave object in order to Clone the Wave object. In my long experience this has been always a cause of subtle bugs when someone adds a new data member to Wave and forgets to add the necessary changes for the Cloning method. So for this project, you are right, it's controlled, but in general I always advocate the MemoryStream approach.
ReplyDeleteI'm getting an odd error when I try to implement the code. It throws a Serialization Excpetion that Type 'WaveViewer.WaveDisplayForm' in Assembly 'WaveViewer'is not marked as serializable. my Wave class is already marked as [Serializeable] For s&g's I marked WaveMgr and WaveDisplayForm as [Serializable]. Now it says System.Windows.Forms.Form is not marked as Serializable.
ReplyDeleteAny suggestions on how to continue troubleshooting?