locked
Odd ComboBox behaviour RRS feed

  • Question

  • Hi, I'm getting a strange behaviour with a ComboBox control, I'll try to make the situation clear:

    I have a DataTable, wich is correctly filled by a SqlDataAdapter, used as DataSource for my ComboBox.

    I correctly set the DisplayMember and ValueMember properties and the ComboBox displays and it also returns the correct value after the user has clicked on it.

    The problem lies here: I need to set the SelectedValue property before the user can do any interaction (I have to display a specific name) but before the ComboBox has been clicked, no matter what I do, the SelectedValue has always a null value!!!

    I even tried something like: comboBox.SelectedValue = new Object();
    but it does not work at all.

    Any clues?

     

    Thanks

    Tuesday, March 21, 2006 12:49 PM

Answers

  • There are some things to be aware of.
    1) When you set the SelectedValue property , the combobox component will try to find the item in your datasource  that has the same value you set, so other properties like SelectedItem reflect the current selection. If the value you are trying to set as SelectedValue is a ValueType ( int, float,..), then boxing will occur, generating an Object that is going to be compared with the datasource. ( say Object A ). so when iterating over the datasource looking for the item with the value you are trying to set, a comparisson between (Object A) and the value at the column you defined as valuemember will occur, and because object comparisson is determined by reference  equality and NOT the value,, then none of the items of the datasource will be set as the SelectedItem, wich mens that trying to access SelectedValue again will return null.

    So if the column that you specify as ValueMember has a basic type, thats whats happening.
    A posible solution is to create a wrapper class and override equality comparisson operator, so when two instances of the wrapper class are compared, the criteria will be the value and not reference equality.

    Tuesday, March 21, 2006 8:56 PM

All replies

  • Have you tried this?

    If combobox.Items.Count > 0 then

       comboBox.selectedIndex = 0

    End If

    Tuesday, March 21, 2006 4:41 PM
  • Actually that may not solve your problem as you said you needed to select a specific value, not the first value.  Can you post the exact code you are using including how you are binding the combobox to the datasource?
    Tuesday, March 21, 2006 4:46 PM
  • Here it is, but let me add that using the SelectedIndex property will not wok because my Item list is empty (I'm using a DataSource).

    [code]

    SqlCommand selectCommand = new SqlCommand();
    selectCommand.CommandType = CommandType.StoredProcedure;
    selectCommand.CommandText = storeProc;
    selectCommand.Connection = Program.connection.theConnection;

    SqlDataAdapter sqlAdapter = new SqlDataAdapter();
    sqlAdapter.SelectCommand = selectCommand;

    DataTable data = new DataTable();
    sqlAdapter.Fill(data); 

    combo.DataSource = data;
    combo.DisplayMember = DisplayMember;
    combo.ValueMember = ValueMember;
    combo.SelectedValue = data.Rows[0][ValueMember];

    [/code]

    Tuesday, March 21, 2006 4:57 PM
  • Hmmm.  I use selectedindex all the time on my bound combos and listboxes and it works just fine.  I like to default to the first item in the list after a save or delete operation.

    Your item list should most definitely *not* be empty.  All of my combos are bound to datatables and I just checked their items.count properties - all greater than zero. 

     

    BTW is this VS2003  or VS2005?

    Tuesday, March 21, 2006 8:18 PM
  • Well: this really looks like an odd behaviour then.

    My ComboBox Item list is empty, it's Count is zero, but the items are correctly displayed and the correct SelectedValue is set when the user interacts.

    And this happens for all the combos in the form.

    Call for help: "MICROSOFT!!!"

    Tuesday, March 21, 2006 8:23 PM
  • There are some things to be aware of.
    1) When you set the SelectedValue property , the combobox component will try to find the item in your datasource  that has the same value you set, so other properties like SelectedItem reflect the current selection. If the value you are trying to set as SelectedValue is a ValueType ( int, float,..), then boxing will occur, generating an Object that is going to be compared with the datasource. ( say Object A ). so when iterating over the datasource looking for the item with the value you are trying to set, a comparisson between (Object A) and the value at the column you defined as valuemember will occur, and because object comparisson is determined by reference  equality and NOT the value,, then none of the items of the datasource will be set as the SelectedItem, wich mens that trying to access SelectedValue again will return null.

    So if the column that you specify as ValueMember has a basic type, thats whats happening.
    A posible solution is to create a wrapper class and override equality comparisson operator, so when two instances of the wrapper class are compared, the criteria will be the value and not reference equality.

    Tuesday, March 21, 2006 8:56 PM
  • If by basic type you are referring to a type such as "string" then I don't find what you have written to be true.  I have a combobox with a value and display member set to a datatable column with a type of string.  In the code (I just tested this) I set the SelectedValue to an arbitrary value that I knew was in the list.  It worked just fine.
    Tuesday, March 21, 2006 9:17 PM
  • you are right,, i wasnt being specific
    i wasnt refering to basic types, but Value Types, string doesnt count (because with strings there is no boxing).

    so what i mean was, int, float, double, any struct

    Tuesday, March 21, 2006 9:20 PM
  • Fair enough, but I still don't find that to be true.  Here is the code I just tested.  The names are irrelevant, but what is relevant is that the ValueMember property is set to a column ("TypeID") that is of type integer.  When I set the selected value to an arbitrary number, the correct value is displayed.  Maybe I am just misunderstanding you:

     

    Private Sub test_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Using ta As New EMLiteDataSetTableAdapters.TypeTableAdapter
    ta.Fill(EMLiteDataSet.Type)
    End Using
    cboType.DisplayMember = "TypeName"
    cboType.ValueMember = "TypeID"
    cboType.DataSource = EMLiteDataSet.Type
    cboType.SelectedValue = 48
    End Sub

     

    Tuesday, March 21, 2006 9:30 PM
  • I guess this is one of those cases in which C# and VB Objects differ quite a lot in implementation....

    Anyway: I'll try to write my very own class, but I find it pretty stupid that the comparison is done on reference instead of values, even more because it's not clearly stated anywhere in the Library. It would have made more sense to me to grant a method for setting the equality operator and advertising the coder.

    But this is just my 2 cents, thanks for the attention to the both of you!

    Tuesday, March 21, 2006 10:58 PM
  • Try this

    Private Sub test_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim newValue as byte
    Using ta As New EMLiteDataSetTableAdapters.TypeTableAdapter
    ta.Fill(EMLiteDataSet.Type)
    End
    Using
    cboType.DisplayMember =
    "TypeName"
    cboType.ValueMember =
    "TypeID"
    cboType.DataSource = EMLiteDataSet.Type
    cboType.SelectedValue = newValue
    End Sub

    Im having the same problem... If I do SelectedValue = 1 it works, if I do SelectedValue = variable it doesnt....

    Tuesday, July 11, 2006 10:35 PM