15

I want to display a custom collection in a DataGridView in a Windows Forms app. This custom collection implements ICollection, and IEnumerable. I have set up a BindingSource, using the collection as the .DataSource property. The DataGridView is set to use my BindingSource as it's DataSource. When I add a new item to the collection using the BindingSource.Add() method, the DataGridView updates correctly with the new item. The BindingSource DataSource, on the other hand, does not:

MyCustomCollection myCollection = new MyCustomCollection();

myCollection.Add(myCustomObject1);
myCollection.Add(myCustomObject2);

myBindingSource.DataSource(myCollection);
myBindingSource.Add(myCustomObject3);

In the above code, myBindingSource's internal List contains the right number of records (3), and the DataGridView also contains three records, but myCollection contains only two records. I know that changing the underlying myCollection will NOT update the BindingSource or the DataGridView, as it is not a BindingList<T>, but I was under the impression that updating a BindingSource directly would ensure that myCollection was updated at the same time.

Is there a way to use a collection that isn't a BindingList<T> and have it updated when interacting with the BindingSource directly?

Update: One way I've gotten the data updated across all the parts (Collection, BindingSource, DataGridView) is as follows:

myCollection.Add(myCustomObject3);
myBindingSource.DataSource = null;
myBindingSource.DataSource = myCollection;

I'm pretty sure there's a better way to attack this problem, but this is the only method that's generated the results I was expecting.

Jeff Clare
  • 185
  • 1
  • 1
  • 8
  • I answerd this question on the following thread https://stackoverflow.com/questions/35275335/convert-a-treeview-to-json-using-c-sharp/54845249#54845249 – Arnaldo Perez Feb 28 '19 at 13:09

4 Answers4

9

The problem is Fill Adaptor. When you load your form, the Fill is done for you. Just make sure to do a Refill and then follow up with Reset bindings post any data changes and Grid will get refreshed.

Example :

WorkTableAdapter.Insert(objData.XAttribute, "",
  objData.YAttribute,objLoanData.Amount_IsValid, DateTime.Now, DateTime.Now);
this.WorkTableAdapter.Fill(this.POCDataSet.Work);
this.WorkBindingSource.ResetBindings(false);
Kyll
  • 7,036
  • 7
  • 41
  • 64
Frank
  • 106
  • 1
  • 2
3

You will have to manually call ResetBindings() after the data source changes if you use a container that cannot do that on your behalf.

http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.resetbindings.aspx

Causes a control bound to the BindingSource to reread all the items in the list and refresh their displayed values.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • 1
    I've looked at ResetBindings(), but it has not produced the correct result. From looking over the documentation, the example seems to indicate that ResetBindings() should be called if I update the underlying collection, instead of the BindingSource directly. – Jeff Clare Jan 28 '13 at 21:35
3

Resetting an individual item works!

I had no luck with .ResetBindings(false) and re-assigning the datsource caused flickering with potentiail overhead if only one item change frequently.

I tried the built in mechanism using PropertyChanged but nothing updated.

Reseting an individual item using ResetItem() worked!

        for (int i = 0; i < bindingSource1.Count; i++)
        {
            bindingSource1.ResetItem(i);   
        }

And even better - if you have an update event attached to each data item in the bindningsource you can locate the object in the bindning source and use the index of the object to call ResetItem(idx)

In this case my custom event args contains a dictionary key to the data object contained in a separate collection. After object is located in using bindningsource.IndexOf() it is individually refreshed.

    void Value_PropertyChanged(object sender, RegisterEventArgs e)
    {

        var idx = bindingSource1.IndexOf(registers_ref[e.registerID]);
        if (idx>=0)
        {
            bindingSource1.ResetItem(idx);                
        }

    }
tofo
  • 388
  • 3
  • 8
1

I believe I ran into this issue a while ago - I did a find in files on my code and I think this is the solution that worked for me.

        // Applies pending changes to the underlying data source.
        this.bindingSource1.EndEdit();

This was in the context of a click handler for the save button.

Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • Thanks for the tip! I tried this, and it had no effect. Documentation for EndEdit seems to indicate that it would do nothing if the objects contained by the datasource do not implement 'IEditableObject'. [Link](http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.endedit.aspx) – Jeff Clare Jan 30 '13 at 14:50
  • +1 this worked for me.. i added it not in button context but in the thread that re-attaches the bindingSource to the grid.DataSource – Raghav Jul 16 '13 at 05:35
  • This kind of worked for me, but for some strange reason, doesn't work on first change but does on subsequent changes, – Josh Mc Jul 28 '20 at 23:20