0

I have a windows form with a ComboBox DisplayBox. In my ViewModel I now have a Property BindingList<MyObject> ObjectBindingList that I want to bind to the DisplayBox.

When I load the form, the DisplayBox does not show any text.

The property DataSource is set and holds a List of MyObjects when checking in the debug modus after the data download. The property items always has a count of zero.

My code works as following:

On startup I set the databindings in the form class to a still empty List ObjectBindingList.

displayBox.DataSource = ObjectBindingList;

The DisplayMember and ValueMember were set in the ComboBox Properties in the GUI Designer.
Asynchrously the controller downloads some data (MyDataObjects) async. Then sets the BindingList<MyObject> ObjectBindingList in the ViewModel to the downloaded Objects through adding them.

Sam
  • 323
  • 2
  • 8
  • [Debug](https://learn.microsoft.com/en-us/visualstudio/get-started/csharp/tutorial-debugger?view=vs-2019). Set a breakpoint on the line shown above and inspect the collection `ObjectBindingList`. Are there any items in there? Note: if you are using a `BindingSource` obect, then assign the binding list to the `DataSource` of the binding source, not to the combobox directly. – Olivier Jacot-Descombes Sep 14 '21 at 16:30
  • Is `ObjectBindingList` a `List` or a `BindingList`? You mentioned both. -- Did you reset the bindings, after you added items to the `List(?)`? – Jimi Sep 14 '21 at 16:44
  • @Jimi It is an BindingList and the binding list is cleared and then filled with the ObjectBindingList.Add( downloadData[i].MyObject ) function. – Sam Sep 15 '21 at 07:13
  • @OlivierJacot-Descombes No, as the download did not yet happen when I bind the data, the ObjectBindingList is set but has no items ( items.count = 0). I want to set the actual data after the download finished and update the ComboBox accordingly. – Sam Sep 15 '21 at 07:25
  • How are adding the data? – Olivier Jacot-Descombes Sep 15 '21 at 13:29
  • @OlivierJacot-Descombes. In my ViewModel I now assign the downloaded object list as a new BindingList to ObjectBindingList. In my solution I am then updating ComboBox with BindingSource.DataSoure = ObjectBindingList. Is there a better /cleaner way? – Sam Sep 15 '21 at 14:18

2 Answers2

0

It seems like when trying to update the ComboBox from a different thread than the main forms thread, the update did not reach the control. I am now using the Invoke Method together with a BindingSource Object in between the Binding List and the control.

private void SetBindingSourceDataSource( BindingList<MyObject> myBindingList)
{
    if (InvokeRequired)
    {
        Invoke(new Action<BindingList<MyObject>>(SetBindingSourceDataSource),  myBindingList);
    }
    else {
        this.BindingSource.DataSource = myBindingList;
    }
}

I am expeciall calling the above function on a PropertyChanged event, that I trigger at the end of every call of the download Function.

Sam
  • 323
  • 2
  • 8
0

Since I don't see all of the relevant code, I can only assume what's happening.

Probably, you don't see the data in the ComboBox, because you are creating a new BindingList when loading the data. But the ComboBox is still attached to the old empty list.

You initialize the data source with an empty list like this:

// Property
BindingList<MyObject> ObjectBindingList { get; set; }

Somewhere else

// Initializes data source with an empty `BindingList<MyObject>`.
ObjectBindingList = new BindingList<MyObject>();
displayBox.DataSource = ObjectBindingList;

Later, you load the data and replace the list:

ObjectBindingList  = LoadData();

Now, you have two lists: the initial empty list assigned to displayBox.DataSource and a new filled one assigned to the property ObjectBindingList. Note that displayBox.DataSource does not have a reference to the property itself, therefore it does not see the new value of the property.

For a BindingList<T> to work as intended, you must add the items with

var records = LoadData();
foreach (var data in records) {
    ObjectBindingList.Add(data);
}

I.e., keep the original BindingList<MyObject> assigned to the data source.


See also: How can I improve performance of an AddRange method on a custom BindingList?


To avoid the problem, I would be advisasble to make the property read-only (using C# 9.0's Target-typed new expressions).

BindingList<MyObject> ObjectBindingList { get; } = new();
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188