5

I am creating a ComboBox array dynamically and the DataSource for all the ComboBox is a single integer list that contains some integers. But when I change a value say X in any one combo box then all other combo values get reset to value X.

So here is the situation:

  • All combo box controls are bound to a single list
  • When I change selected item of a combo box, selected item of all other combo box controls also change.

How can I stop these behavior?

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Dinesh wakti
  • 121
  • 2
  • 8
  • Hello, can you detail which language and libs are you using? – Sommerwild Mar 08 '16 at 10:35
  • I am using c# winforms – Dinesh wakti Mar 08 '16 at 10:39
  • Each row of the form has an unbound combo box. Though the combo box appears in each row of the form, if I change the value in the combo box in any one row, it changes all the combo boxes in every row, forcing all the combo boxes to the same value. How can I make each combo box (in each row) behave "independently?" – Dinesh wakti Mar 08 '16 at 10:46
  • It's because all combo boxes are bound to a single source. – Reza Aghaei Mar 08 '16 at 11:03

1 Answers1

14

Since you are binding all combo boxes to the same data source - a single list - they are using a single BindingManagerBase.

So when you choose an item from one of combo boxes, the current Position of the shared binding manager base changes and all combo boxes goes to that position of their shared data source.

To solve the problem you can bind them to different data source:

  • You can bind them to yourList.ToList() or any other list for example different BindingList<T>.

    combo1.DataSource = yourList.ToList();
    combo2.DataSource = yourList.ToList();
    
  • You can use different BindingSource for them and set your list as DataSource of BindingSource

    combo1.DataSource = new BindingSource { DataSource= yourList};
    combo2.DataSource = new BindingSource { DataSource= yourList};
    

Also as another option:

  • You can use different BindingContext for your combo boxes. This way even when you bind them to a single list, they are not sync anymore.

    combo1.BindingContext = new BindingContext();
    combo1.DataSource = yourList;
    combo2.BindingContext = new BindingContext();
    combo2.DataSource = yourList;
    

In fact all controls of the form use a shared BindingContext. When you bind 2 controls to a same data source, then they also use the same BindingManagerBase this way, when you for example move to next record, all controls move to next record an show value from bound property of next record. This is the same behavior that you are seeing from your combo boxes. Being sync for controls which are using the same BindingManagerBase is a desired behavior. Anyway sometimes we don't need such behavior. The post shares the reason and the solution.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • How do i set the value for this combobox – Dinesh wakti Mar 08 '16 at 12:57
  • 1
    Using `combo1.BindingContext = new BindingContext();` Worked like a charm – Mohammad Qasim Jan 04 '17 at 06:24
  • It should be noted that `combo2.DataSource = yourList.ToList();` creates a __copy__ of the data. Great if they shall be edited independently. Not so good when then are big and not supposed to change.. – TaW Apr 09 '18 at 19:50
  • @TaW To clarify for future readers, I should mention, in fact `ToList` and `DataView` don't create a copy of data, they have just some pointers to the original data. Users should not compare them with creating a deep copy of the `List` or cloning the `DataTable`. In general creating `ToList` or `DataView` has some impacts on performance, but for most cases the impact is negligible. – Reza Aghaei Apr 09 '18 at 19:57
  • Hm, if that is true for ToList() I have to retract my comment; usually ToList() does create a copy of the underlying enumerable data, doesn't it? – TaW Apr 09 '18 at 19:59
  • @TaW If you don't mean doing a deep copy, yes it creates a new list containing the same object references. – Reza Aghaei Apr 09 '18 at 20:02
  • It's similar to `var o = new Object();` and then `var o2 = o;`. While we created the new variable, but we are using the same object. And the overhead, as far as I know, is because of a loop to create a new enumerable. Here is a [related link](https://stackoverflow.com/questions/15516462/is-there-a-performance-impact-when-calling-tolist). – Reza Aghaei Apr 09 '18 at 20:09
  • 'object references', of course it won't do a deep copy; but quite often the data in the data source are plain values.. – TaW Apr 09 '18 at 20:09
  • Properties are not important, but `` is important. If `T` is, then there is no problem. If it's structure, data will be duplicated. – Reza Aghaei Apr 09 '18 at 20:11
  • Probably what I'm saying is obvious, but I just wanted to make sure users will not compare `ToList` to creating a new `List` and then for each object, create a clone copy and add to list. – Reza Aghaei Apr 09 '18 at 20:12
  • Another [related link](https://stackoverflow.com/questions/2774099/tolist-does-it-create-a-new-list) – Reza Aghaei Apr 09 '18 at 20:20
  • The default chain behavior is so weird. While I claim the list to be ReadOnly, it's a clear indication that they are for individual display only, sharing the same readonly content is so common why would I have to copy it for every combo box . – joe Mar 10 '21 at 08:43
  • @joe ComboBox or ListBox or DataGridView support a special kind of data binding which is called complex data binding. In this scenario, those controls will represent a list of items and usually play role of an index (a list) of a few items. They will have a property like Position, which is the selected index of the list, a Current property which is the current item of the list ... – Reza Aghaei Mar 10 '21 at 09:22
  • ... The way those controls implement this kind of data binding is by using a BindingContext class. There is by default an instance of BindingContext class which belongs to the form and all the controls use the same instance as their binding context. So for example when listBox1 internally looks for the data source, it uses BindingContext[data] to find the binding context (which has Position and Current) properties ... – Reza Aghaei Mar 10 '21 at 09:24
  • ... Now it should be visible why selected index of listBox1 and listBox2 is synchronized, that's because the selected index is bound to the position, which is coming from `BindingContext[data].Position` and since the BindingContext instance and the data instance are same, it returns the same BindingContext for all the bound controls and changing the position in one of the controls, change the position in the other as well ... – Reza Aghaei Mar 10 '21 at 09:27
  • ... Now you should be able to see where the idea of proposed fixes are coming from: I am suggesting different BindingContext objects or Different lists, which basically means BindingContext[data] will be different for each control. – Reza Aghaei Mar 10 '21 at 09:27
  • @joe I just wrote above comments without debugging or reading the source code; just wrote based on what I had over my head at the moment, they may be not 100% accurate in all the details, but they are correct in general. – Reza Aghaei Mar 10 '21 at 09:38