2009-07-29

This is not the SelectedValue you're looking for

Oh, here's a fun one.

I have a list of locations that I'm retrieving from a web service, and I want to display them in a ComboBox. I also want to have a blank entry at the top of the list, so "nothing" can be selected. While I'm sure there are ways to do this with less code, creating binding objects and such (especially since the retrieved object list is already pre-sorted in the order I want), I've resorted to just creating a DataTable with an ID and display column and copying the values I want into it. It does make things easier when I have one combo box filter another, as DataTables already have code written for searching and filtering.

Anyway, after I get my data, I have a DataTable that looks like this:

LocationIdLocation
DBNull.ValueString.Empty
2Aurora
7Colorado Springs
1Denver
3Ft. Collins
4Longmont
6Parker

Now, I bind it to my ComboBox like this:

combo1.DataSource = dataTable;
combo1.DisplayMember = "Location";
combo1.ValueMember = "LocationId";

Note that you have to set the DataSource first and the DisplayMember & ValueMember properties second, otherwise you get a ComboBox full of "System.Data.DataRow". Nice.

Now, on this form, when a value is selected, the selected value is used to filter another list; and, when the form is submitted, the selected value is passed off to a web service. How do you find out when a value is selected, and what that value is? Simple; bind to the SelectedValueChanged event, and query the SelectedValue property, right? In theory.

In practice, no. To make a long story short, I dropped a label onto the form so I could see what was going on in "real time". First, the code:

private void combo1_SelectedValueChanged(object sender, EventArgs e) {
     label1.Text = Convert.ToString(combo1.SelectedValue) + " - " + Convert.ToString(((System.Data.DataRowView)(combo1.SelectedItem))["LocationId"]);
}

And the results:

ComboBox selectionLabel1.Text
empty - 
Aurora1 - 2
Colorado Springs2 - 7
Denver3 - 1
Ft. Collins4 - 3
Longmont6 - 4
Parker7 - 6

Incidentally, the SelectedText property was always blank.

On the up-side, as you can see, I found a way to get the real value (using the SelectedItem and casting appropriately). On the down-side, it means I have to use that construction to get the selected value on this and every other similar ComboBox (there are actually four on this form alone), since SelectedValue, apparently, doesn't.

2 comments:

Spencer said...

I see 1, 2, 3, 4, 6, and 7 - whatever happened to 5?

Yakko Warner said...

I deleted it intentionally. I wanted to make sure I was looking at database IDs and not, say, index or sequence numbers. If there was no 5 in the database but I saw a 5 in code, then I would know the numbers had nothing to do with the actual IDs.

I played with it some more and noticed that, somehow, the ComboBoxes' Sorted property were set to True (instead of the default False — don't know how that got switched, I know I didn't change it).

I did switch that to False, but it was long after I removed the code checking SelectedValue, so I don't know if that would've fixed it. If that is what caused it, then it would appear Sorted sorts the Values so they no longer are in sync with the actual items.

Oh yeah. That's useful.