0

I have an entity, e.g. customer inherited from IEditableObject, like described here:

public class Customer : IEditableObject
{
    ...
    private Boolean backupAvailable = false;
    private ThisObject backupData;

    public void BeginEdit()
    {
        if (!backupAvailable)
        {
            this.backupData.Name = this.Name;
            backupAvailable = true;
        }
    }

    public void CancelEdit()
    {
        if (backupAvailable)
        {
            this.Name = this.backupData.Name;
            backupAvailable = false;
        }
    }

    public void EndEdit()
    {
        if (backupAvailable)
        {
            backupData = new ThisObject();
            backupAvailable = false;
        }
    }
}

In my UI class I have a BindingSource, where all controls are bind to, and 2 buttons "Change" and "Cancel":

BindingSource BSCustomer;

private void buttonChange_Click(object sender, EventArgs e)
{
    ...
    ((Customer)BSCustomer.Current).BeginEdit();
}


private void buttonCancel_Click(object sender, EventArgs e)
{
    ...
    ((Customer)BSCustomer.Current).CancelEdit();
}

This works fine.

But now I've detected, that BeginEdit() is not only called from my explicit call, but called from many other code, e.g.:

BSCustomer.AllowNew = true;

or

BSCustomer.AddNew();

or

BSCustomer.IndexOf();

When I click now the button "Change", backupAvailable is already set with wrong values. When I click "Cancel" the wrong values are wrote back.

Are there any possibilities to prevent this callings? Or can I differ in BeginEdit() where the call comes from?

Beetee
  • 475
  • 1
  • 7
  • 18
  • Hi, I'm afraid this is "by design", i.e. `BeginEdit` is called from many places in WF data binding infrastructure "just in case". That's why the `bool` flag is needed. If you want to control exactly when `BeginEdit`, `CancelEdit` and `EndEdit` are called, keep the `Customer` class methods as they are currently, but don't implement `IEditableObject` (remove `: IEditableObject`). – Ivan Stoev Aug 22 '17 at 10:42
  • You are right. I created a DataGridView - BindingSource - BindingList - IEditableObject chain, and noticed that during initialisation of the BindingSource the BeginEdit of the first element of the BindingList is called several times. EndEdit / CancelEdit is not called. Moving around in the DataGridView using keyboard (not editing!) also causes BeginEdit to be called several times, without EndEdit / CancelEdit. Apparently these functions can't be used trustworthy to create undo functionality – Harald Coppoolse Aug 22 '17 at 11:16
  • 1
    Hi Ivan, removing the `IEditableObject` did the trick. Now `BeginEdit()` is just called when I call it manually. Thx. – Beetee Aug 22 '17 at 11:51

2 Answers2

1

Just removing :IEditableObject is the solution. Without that, BeginEdit() is just called when it's called manually.

All the credits to Ivan.

Beetee
  • 475
  • 1
  • 7
  • 18
0

I also had to deal with this situation. Thank you Ivan, they helped solve this problem. As a result, I did something like this with ICloneable.

public class Customer : ICloneable
{
    struct ThisObject 
    {
        internal string guid;
        internal string name;
    }

    private Boolean backupAvailable = false;
    private ThisObject backupData;
    private ThisObject currentData;

    public void BeginEdit()
    {
        if (!backupAvailable)
        {
            var tempCustomer = (Customer)this.Clone();
            this.backupData = tempCustomer.currentData;
            backupAvailable = true;
        }
    }

    public void CancelEdit()
    {
        if (backupAvailable)
        {
            this.currentData = backupData;
            backupAvailable = false;
        }
    }

    public void EndEdit()
    {
        if (backupAvailable)
        {
            backupData = new ThisObject();
            backupAvailable = false;
        }
    }

    public Customer() : base()
    {
            this.currentData = new ThisObject();
            this.currentData.guid = Guid.NewGuid().ToString();
            this.currentData.name = string.Empty;
    }

    public string GUID
    {
        get { return this.currentData.guid; }
        set { this.currentData.guid = value; }
    }

    public string Name
    {
        get { return this.currentData.name; }
        set { this.currentData.name = value; }
    }

    public object Clone()
    {
        return (Customer)this.MemberwiseClone();
    }
}

...

private void buttonChange_Click(object sender, EventArgs e)
{
    ...
    ((Customer)BSCustomer.Current).BeginEdit();
}


private void buttonCancel_Click(object sender, EventArgs e)
{
    ...
    ((Customer)BSCustomer.Current).CancelEdit();
}
Dinariys
  • 11
  • 3