Wednesday, May 28, 2008

Creating Objects that Support Edit Cancellation via IEditableObject

This blog is from - http://blogs.infragistics.com/blogs/joshs/archive/2008/05/08/creating-objects-that-support-edit-cancellation-via-ieditableobject.aspx
Creating Objects that Support Edit Cancellation via IEditableObject

The IEditableObject interface provides controls with a way to allow a data source to react intelligently to being edited. This might seem superfluous, until you consider that complex controls, such as a data grid, allow the user to cancel an editing session via the Escape key.

For example, suppose the user is editing a row in the UltraGrid or XamDataGrid, and then realizes that he has been editing the wrong row. If he presses the Escape key once, the grid automatically reverts the active cell to the value it had before editing began. If the user hits Escape again, the entire row reverts to the values it had before the user started to edit its cells.

If the grid is bound to an ADO.NET container, such as DataTable, all of this magic happens for us automatically. However, if the grid is bound to a collection of your own objects, such as custom business objects, this will not happen by default. Your business objects will need to implement that logic, just as the ADO.NET containers do. Perhaps your business objects will not implement that functionality, since it is not part of any business domain, but Presentation Model objects might, instead. Regardless of the lingo, at the end of the day you will need to implement this logic somewhere!

Fortunately, this is quite easy to do. The IEditableObject interface is all you need to implement, as seen below:

private BinaryFormatter _formatter = new BinaryFormatter();
private MyData _myState;
private MemoryStream _snapshot;


void IEditableObject.BeginEdit()
{
if (_snapshot != null)
return;

_snapshot = new MemoryStream();
_formatter.Serialize(_snapshot, _myState);
}

void IEditableObject.CancelEdit()
{
if (_snapshot == null)
return;

// Restore our state to the snapshot taken when the editing session began.
_snapshot.Position = 0;
_myState = _formatter.Deserialize(_snapshot) as MyData;
this.ThrowAwaySnapshot();
}

void IEditableObject.EndEdit()
{
this.ThrowAwaySnapshot();
}

void ThrowAwaySnapshot()
{
if (_snapshot != null)
{
_snapshot.Dispose();
_snapshot = null;
}
}

This code assumes the MyData type (and all of its ancestor types) is decorated with the Serializable attribute, since it is serialized by the BinaryFormatter.

The BeginEdit method starts with a check to see if we are already in an editing session. If so, it immediately returns since there can only be one editing session at a time. There is no guarantee regarding when and how often that method will be invoked, so this precautionary step is necessary. When a new editing session begins, a snapshot of the object's state is taken and stored in a MemoryStream.

If the user cancels the editing session, the CancelEdit method executes. That method deserializes the snapshot taken in BeginEdit, and applies the saved values to the editable object. If the IEditableObject instance contains the various fields being edited, instead of having a reference to one object that contains all the values, your CancelEdit method will include code that sets all of those fields to whatever values were saved in the BeginEdit method.

When the user completes an editing session (i.e. finishes editing a row in the grid) the EndEdit method is invoked. That gives us a chance to dispose of the snapshot data. Once the snapshot is removed, a subsequent call to BeginEdit will cause a new editing session to begin.

No comments: