Search code examples
c#winformsbindingsource

How to cancel all changes in a bindingSource?


I have two buttons - cancel and add that adds a new row in a grid view and respectively each time I click it, a new record is added to the context, which is connected to a binding source, which is set as a data source of the grid view.

So if I have 2 rows and add 8 rows(for example), when I click cancel, it should only clear the unsaved rows and leave them to two again.

The problem is that it only cancels 4 of them(i can see the problem in my code, but i can't find a way to fix it).

Here is my simple code, that doesn't work so far:

try
        {
            DialogResult dialogResult = MessageBox.Show("Do you want to cancel all unsaved changes?", "Cancel all unsaved changes", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                for (var i = 0; i < bindingSource1.Count; i++)
                {
                    var f = bindingSource1[i] as MyConfiguration;

                    if (f.MyConfigurationId == 0)
                    {
                        context.RemoveMyConfiguration(f);
                        bindingSource1.Remove(f);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

The problem is that I iterate through the binding source and remove elements in the same time and it gets updated, so at some point it can see that it has looped through the whole collection.

What is the correct way? Should I loop through the rows in the grid?

EDIT: I apologize for that, it's WinForms. The BindingSource's data source is List that comes from the database. I am using entity framework 4.0.


Solution

  • Your issue is simply that you remove items from the list you are itterating through. If you remove an item from the BindingSources list, the items ahead of it are moved one index back, meaning that you will skip the item that has been relocated to the index you removed the item from.

    The simplest solution is to move your increment of the counter to an else block, so that the counter is only incremented if an item is NOT removed, otherwise you wish to check the same index again, as a new item now occupies this index.

    Bonus-info: I would recomend taking a look at the BindingList, and consider using this as a datasource for your BindingSource instead of a normal List<T>. The main advantage with using a BindingList in combination with a bindingsource is that the bindinglist fires events when the list is changed, these events are subscribed by the bindingsource. This means that you only have to "worry" about making changes to your BindingList instance - changes are picked up by the bindingsource and reflected in the controls using the bindingsource as datasource.

    Super-Mega-Jackpot-info: If you wish to cancel changes made on a single item in the BindingSource (found in the Current property), you can use the method CancelEdit. But for this to have any effect the object-type contained in the bindingsource needs to implement the IEditableObject interface