views:

594

answers:

2

The ComboBox Items collection is an ObjectCollection, so of course you can store anything you want in there, but that means you don't get a Text property like you would with, say, a ListViewItem. The ComboBox displays the items by calling ToString() on each item, or using reflection if the DisplayMember property is set.

My ComboBox is in DropDownList mode. I have a situation where I want to refresh the item text of a single item in the list when it gets selected by the user. The problem is that the ComboBox doesn't re-query for the text at any time besides when it loads up, and I can't figure out how else to do what I want besides removing and re-adding the selected item like so:


PlantComboBoxItem selectedItem = cboPlants.SelectedItem as PlantComboBoxItem;

// ...

cboPlants.BeginUpdate();

int selectedIndex = cboPlants.SelectedIndex;
cboPlants.Items.RemoveAt(selectedIndex);
cboPlants.Items.Insert(selectedIndex, selectedItem);
cboPlants.SelectedIndex = selectedIndex;

cboPlants.EndUpdate();

This code works fine, except for the fact that my SelectedIndex event ends up getting fired twice (once on the original user event, and then again when I re-set the property in this code). In this case, it's not a big deal that the event is fired twice, but it's inefficient, and I hate that. I could rig up a flag so it exits the event the second time, but that's hacking.

Is there a better way to get this to work?

+4  A: 

Hmm... could you use a BindingList<T>, as described here? That way, you could just modify the item in the underlying collection and have it reflected in the ComboBox without having to add or remove anything from the control.

You'd need to have a collection something like this, containing all your items for the ComboBox:

private BindingList<PlantComboBoxItem> plantComboBoxItems;

Then, at some point (like when the program is starting), bind it to the ComboBox:

cboPlants.DataSource = plantComboBoxItems;

Now, you can just modify the collection directly:

plantComboBoxItems[cboPlants.SelectedIndex].doWhateverYouWant();

And changes will be reflected in cboPlants. Is this what you're looking for?

Donut
+1  A: 

Got it, using Donut's suggestion.

In form class:

private BindingList<PlantComboBoxItem> _plantList;

In loading method:

_plantList = new BindingList<PlantComboBoxItem>(plantItems);
cboPlants.DataSource = _plantList;

In SelectedIndexChanged event:

int selectedIndex = cboPlants.SelectedIndex;
_plantList.ResetItem(selectedIndex);

Thank you!

Jon Seigel
As an aside, I wonder why no one thought to include something like a RefreshItem function on the ComboBox.
Jon Seigel
Noooooo... ResetItem() fires the SelectedIndexChanged method :(Oh well, this is still cleaner that my original solution.
Jon Seigel
Do you need to call `ResetItem()`? The item in `cboPlants` should be changed if you just update it directly (I think?). You can access it in the `SelectedIndexChanged` event with `_plantList[selectedIndex]`.
Donut
Yes, I do have to call ResetItem(). The control has no idea to refresh the item otherwise (I tried taking out that line and it didn't update the item when I changed it). The item does not get updated automatically even though the underlying data in the PlantComboBoxItem changed. I think the ResetItem() function must be internally implemented as what I was doing before -- manually removing and then adding the item again. Such a PITA.
Jon Seigel