CancelEdit in BindingSource

  • Thread starter Thread starter BD
  • Start date Start date
B

BD

Hi,

I have a "Cancel" button on a form to cancel any changes in the
current item with the code BindingSource1.CancelEdit but this don't
restore the older's values that had been changed. The
BindingSource.DataSource is a type of BindingList<MyClass>. What's I'm
doing wrong?

[]'s
BD
[]'s
BD
 
BD said:
Hi,

I have a "Cancel" button on a form to cancel any changes in the
current item with the code BindingSource1.CancelEdit but this don't
restore the older's values that had been changed. The
BindingSource.DataSource is a type of BindingList<MyClass>. What's I'm
doing wrong?

Your 'MyClass' has to implement IEditableObject, which makes you
implement BeginEdit, EndEdit and CancelEdit. In the CancelEdit method,
you restore the values the fields had at the time BeginEdit was called.

Warning: this is a time waster. Grids often call BeginEdit a couple of
times, so you have to flag if you're already in edit mode. Also,
CancelEdit can also be called when you created a new row and pressed
ESC to remove the new row. This then has to make sure the new row is
removed from the original list. If you use the pre-fab BindingList, it
should take care of that, but be sure this indeed happens.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
Your 'MyClass' has to implement IEditableObject, which makes you
implement BeginEdit, EndEdit and CancelEdit. In the CancelEdit method,
you restore the values the fields had at the time BeginEdit was called.

Warning: this is a time waster. Grids often call BeginEdit a couple of
times, so you have to flag if you're already in edit mode. Also,
CancelEdit can also be called when you created a new row and pressed
ESC to remove the new row. This then has to make sure the new row is
removed from the original list. If you use the pre-fab BindingList, it
should take care of that, but be sure this indeed happens.

FB


Thank's for your answer. I really don't waste the time to implement
the IEditableObject in all my classes. The BindingList takes care of
call the CancelEdit internal when ESC is pressed, but since I move to
another control, even to the Cancel button used in the form, the
BindingList call the EndEdit internal and I can't undo the properties
changed to the original value. I think I have to extend the
BindingSource control to make a backup of the current item and if I
cancel the changes restore the original values from that backup. I
think this approach would resolve my problem but I have some
difficulties to restore the data into the bounds controls. Any help or
example would be very appreciate.
[]'s
BD
 
Thank's for your answer. I really don't waste the time to implement
the IEditableObject in all my classes. The BindingList takes care of
call the CancelEdit internal when ESC is pressed, but since I move to
another control, even to the Cancel button used in the form, the
BindingList call the EndEdit internal and I can't undo the properties
changed to the original value. I think I have to extend the
BindingSource control to make a backup of the current item and if I
cancel the changes restore the original values from that backup. I
think this approach would resolve my problem but I have some
difficulties to restore the data into the bounds controls. Any help or
example would be very appreciate.
[]'s
BD


Problem solved with FieldInfo class.

[]'s
BD
 
Thank's for your answer. I really don't waste the time to implement
the IEditableObject in all my classes. The BindingList takes care of
call the CancelEdit internal when ESC is pressed, but since I move to
another control, even to the Cancel button used in the form, the
BindingList call the EndEdit internal and I can't undo the properties
changed to the original value. I think I have to extend the
BindingSource control to make a backup of the current item and if I
cancel the changes restore the original values from that backup. I
think this approach would resolve my problem but I have some
difficulties to restore the data into the bounds controls. Any help or
example would be very appreciate.
[]'s
BD


Problem solved with FieldInfo class.

[]'s
BD

What do you mean? I had to implement IEditable and INotifyPropertyChanged
to capture the changes to the object and be able to roll them back.

Robin S.
 
Thank's for your answer. I really don't waste the time to implement
the IEditableObject in all my classes. The BindingList takes care of
call the CancelEdit internal when ESC is pressed, but since I move to
another control, even to the Cancel button used in the form, the
BindingList call the EndEdit internal and I can't undo the properties
changed to the original value. I think I have to extend the
BindingSource control to make a backup of the current item and if I
cancel the changes restore the original values from that backup. I
think this approach would resolve my problem but I have some
difficulties to restore the data into the bounds controls. Any help or
example would be very appreciate.
[]'s
BD


Problem solved with FieldInfo class.

[]'s
BD

What do you mean? I had to implement IEditable and INotifyPropertyChanged
to capture the changes to the object and be able to roll them back.

Robin S.


I did not intend to implement that in all my objects and I made two
generic function to backup and restore the data using Stack<byte[]>,
HybridDictionary, FieldInfo[], MemoryStream and BinaryFormatter.

private Stack<byte[]> _backup;

private void BackupData()
{
if (_backup == null)
{
_backup = new Stack<byte[]>();
object source = BindingSource.Current;
Type sourceType = source.GetType();

HybridDictionary state = new HybridDictionary();

FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = sourceType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);

foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{

object value = field.GetValue(source);

if(sourceType.IsAssignableFrom(field.FieldType))
{
// make sure the variable has a value
if (value == null)
{
// variable has no value - store that fact
state.Add(field.DeclaringType.Name + "!" +
field.Name, null);
}
else
{
// this is a child object, cascade
the call
((this)value).BackupData();
}
}
else
{
// this is a normal field, simply trap the value
state.Add(field.DeclaringType.Name +
"!" + field.Name, value);
}

}
}
sourceType = sourceType.BaseType;
} while (sourceType != null);

// serialize the state and stack it
using (MemoryStream buffer = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(buffer, state);
_backup.Push(buffer.ToArray());
}

}
}

private void RestoreData()
{

// if we are a child object we might be asked to
// undo below the level where stacked states,
// so just do nothing in that case
if (_backup != null)
{
HybridDictionary state;
using (MemoryStream buffer = new
MemoryStream(_backup.Pop()))
{
buffer.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
state =
(HybridDictionary)formatter.Deserialize(buffer);
}

object source = BindingSource.Current;
Type sourceType = source.GetType();

FieldInfo[] fields;

do
{
// get the list of fields in this type
fields = sourceType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{
// the field is undoable, so restore its
value
object value = field.GetValue(source);

if(sourceType.IsAssignableFrom(field.FieldType))
{
// this is a child object
// see if the previous value was empty
if(state.Contains(field.DeclaringType.Name + "!" + field.Name))
{
// previous value was empty -
restore to empty
field.SetValue(source, null);
}
else
{
// make sure the variable has a
value
if (value != null)
{
// this is a child object,
cascade the call.
((this)value).RestoreData();
}
}
}
else
{
// this is a regular field, restore
its value
field.SetValue(source,
state[field.DeclaringType.Name + "!" + field.Name]);
}

}
}
sourceType = sourceType.BaseType;
} while (sourceType != null);

BindingSource.ResetCurrentItem();

_backup = null;

}
}
[]'s
BD
 
Thank's for your answer. I really don't waste the time to implement
the IEditableObject in all my classes. The BindingList takes care of
call the CancelEdit internal when ESC is pressed, but since I move to
another control, even to the Cancel button used in the form, the
BindingList call the EndEdit internal and I can't undo the properties
changed to the original value. I think I have to extend the
BindingSource control to make a backup of the current item and if I
cancel the changes restore the original values from that backup. I
think this approach would resolve my problem but I have some
difficulties to restore the data into the bounds controls. Any help or
example would be very appreciate.
[]'s
BD


Problem solved with FieldInfo class.

[]'s
BD

What do you mean? I had to implement IEditable and INotifyPropertyChanged
to capture the changes to the object and be able to roll them back.

Robin S.


I did not intend to implement that in all my objects and I made two
generic function to backup and restore the data using Stack<byte[]>,
HybridDictionary, FieldInfo[], MemoryStream and BinaryFormatter.

private Stack<byte[]> _backup;

private void BackupData()
{
if (_backup == null)
{
_backup = new Stack<byte[]>();
object source = BindingSource.Current;
Type sourceType = source.GetType();

HybridDictionary state = new HybridDictionary();

FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = sourceType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);

foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{

object value = field.GetValue(source);

if(sourceType.IsAssignableFrom(field.FieldType))
{
// make sure the variable has a value
if (value == null)
{
// variable has no value - store that fact
state.Add(field.DeclaringType.Name + "!" +
field.Name, null);
}
else
{
// this is a child object, cascade
the call
((this)value).BackupData();
}
}
else
{
// this is a normal field, simply trap the value
state.Add(field.DeclaringType.Name +
"!" + field.Name, value);
}

}
}
sourceType = sourceType.BaseType;
} while (sourceType != null);

// serialize the state and stack it
using (MemoryStream buffer = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(buffer, state);
_backup.Push(buffer.ToArray());
}

}
}

private void RestoreData()
{

// if we are a child object we might be asked to
// undo below the level where stacked states,
// so just do nothing in that case
if (_backup != null)
{
HybridDictionary state;
using (MemoryStream buffer = new
MemoryStream(_backup.Pop()))
{
buffer.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
state =
(HybridDictionary)formatter.Deserialize(buffer);
}

object source = BindingSource.Current;
Type sourceType = source.GetType();

FieldInfo[] fields;

do
{
// get the list of fields in this type
fields = sourceType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{
// the field is undoable, so restore its
value
object value = field.GetValue(source);

if(sourceType.IsAssignableFrom(field.FieldType))
{
// this is a child object
// see if the previous value was empty
if(state.Contains(field.DeclaringType.Name + "!" + field.Name))
{
// previous value was empty -
restore to empty
field.SetValue(source, null);
}
else
{
// make sure the variable has a
value
if (value != null)
{
// this is a child object,
cascade the call.
((this)value).RestoreData();
}
}
}
else
{
// this is a regular field, restore
its value
field.SetValue(source,
state[field.DeclaringType.Name + "!" + field.Name]);
}

}
}
sourceType = sourceType.BaseType;
} while (sourceType != null);

BindingSource.ResetCurrentItem();

_backup = null;

}
}
[]'s
BD

Cool. Thanks for displaying your solution.

Robin S.
 
Back
Top