Issues with Databound Combobox

timh

Well-known member
Joined
Nov 28, 2008
Messages
50
Programming Experience
Beginner
I am currently having issues with a databound combobox, which I am trying to display as a drop down list.

I thought I had it sorted, but no.

This is my code

VB.NET:
    Private Sub setupFeescbx()
        EntrantBindingSource.RaiseListChangedEvents = False
        With FeecategoryComboBox
            For Each row As DataRow In dsEDX.Tables("entryfees").Rows
                If Not (.Items.Contains(row.Item("category").ToString)) Then
                    .Items.Add(row.Item("category").ToString)
                End If
            Next
            EntrantBindingSource.RaiseListChangedEvents = True
            .DataSource = EntrantBindingSource
            .DisplayMember = "feecategory"
        End With
    End Sub

setupFeescbx is called when the form initially loads and then again if the list of categories is changed (when I want to repopulate the available options).

The selecteditem property of the combobox is bound in its properties table to EntrantBindingSource -feecategory.

The idea is that the combo box displays the value from the EntrantBindingSource, which must also be one of the available options from the "entryfees" table. It seems to work at first sight, as I move forward through the records, but when I go backwards, the text on the combobox changes to "System.Data.Datarowview". Looking at the options in the combobox, there is a list equal in length to the number of records in my dataset, rather than the number of fee categories.

Clearly I am doing something terribly wrong, but I would appreciate being pointed in the right direction please. I realise that even if I do get it working as intended, I will have to somehow handle a category being removed from the list, as presumably that would cause issues if I try to display a record with a value that is no longer available on the drop down list...in my mind, it would revert to a default value that is always in the list.

Thanks for reading!
 
First things first, you have either bind a control or add items directly; you can't do both. You are currently trying to do both:
VB.NET:
    Private Sub setupFeescbx()
        EntrantBindingSource.RaiseListChangedEvents = False
        With FeecategoryComboBox
            For Each row As DataRow In dsEDX.Tables("entryfees").Rows
                If Not (.Items.Contains(row.Item("category").ToString)) Then
                    [B][U][COLOR="#FF0000"].Items.Add(row.Item("category").ToString)[/COLOR][/U][/B]
                End If
            Next
            EntrantBindingSource.RaiseListChangedEvents = True
            [B][U][COLOR="#0000FF"].DataSource = EntrantBindingSource[/COLOR][/U][/B]
            .DisplayMember = "feecategory"
        End With
    End Sub
The red line is adding items directly and the blue line is data-binding. What you should do is bind the DataTable to a BindingSource and bind the BindingSource to the ComboBox, then set the Filter of the BindingSource if you want to limit which items are displayed.
 
Thanks jmcilhinney, however I don't really understand your answer. Perhaps I've posed the question wrong?

I already have a combobox that is successfully bound to an element in the binding source, but which also has drop down list items. This is for "sex" and so the items property is populated in the properties designer with the two values "Male" and "Female".

I am trying to achieve the same thing with FeecategoryComboBox. I can populate it with the values in the properties designer and it works fine, but I am struggling to do the same thing at run time, which I need to be able to do as the categories are defined by the user.

I took a look at the automatic code in the Designer and came up with the following, which works:

VB.NET:
    Private Sub setupFeescbx()
        Dim strTemp As New ArrayList

        With FeecategoryComboBox
            .BeginUpdate()
            .Items.AddRange(New Object() {"UKA affiliated", "UKA affiliated (OTD entry)", "Unaffiliated", "Unaffiliated (OTD entry)"})
            .EndUpdate()
        End With

        EntrantBindingSource.ResetCurrentItem()

    End Sub

...but of course I want to create that array from values in the "entryfees" table.

Hopefully that is a simple matter of iterating through the rows of the "entryfees" table and adding the value of "category" to an array. Just need to work out how to do that...but not tonight.
 
If you want to bind data to the control then DO NOT add items to it directly. Can you not see that calling Items.AddRange is adding items? If you want to bind then you set the DataSource.
 
Obviously I'm being rather thick here, but I don't see that what I'm trying to do is so unusual? After all, people use comboboxes all the time to limit user input, e.g. sex (Male/Female).

I'm working with a database of "entrants" and when inputting a new entrant, I want the inputter to have to select a value of "feecategory" from a drop down list, as this will then define the entry fee. But I also want the combobox to display the appropriate value for the current entrant as you step through the records, hence it is bound to "EntrantBindingSource".

I added the combobox from the datasources tab in the designer and ditto with the one for sex. The one for sex is easy, because there can only be two options and they can be added at design time. Fee category is different, because those are defined by the user when the program is running and are stored in a separate table ("entryfees"). I'm not trying to bind the combobox to the "entryfees" table, just use the list of categories as the options available to select.

Anyway, this now works. But have I created a time bomb in my code?

VB.NET:
    Private Sub setupFeescbx()
        Dim strTemp(dsEDX.Tables("entryfees").Rows.Count - 1) As String

        For i = 0 To dsEDX.Tables("entryfees").Rows.Count - 1
            strTemp(i) = dsEDX.Tables("entryfees").Rows.Item(i).Item("category")
        Next

        EntrantBindingSource.RaiseListChangedEvents = False
        With FeecategoryComboBox
            .BeginUpdate()
            .Items.Clear()
            .Items.AddRange(strTemp)
            .EndUpdate()
        End With
        EntrantBindingSource.RaiseListChangedEvents = True
        EntrantBindingSource.ResetCurrentItem()

    End Sub

Please excuse my ignorance, I'm no professional.
 
Last edited:
No, what you want to do is not unusual at all but what is unusual is the number of times you have completely ignored what I have posted DO NOT add items to the Items collection. DO set the DataSource property. I'm not going to waste my time repeating that any further.
 
No, what you want to do is not unusual at all but what is unusual is the number of times you have completely ignored what I have posted DO NOT add items to the Items collection. DO set the DataSource property. I'm not going to waste my time repeating that any further.

OK, after feeling a little aggrieved by your comments, I had a light bulb moment...it was that easy. I assumed that the datasource was what I was binding the control to (i.e. the "entrants" datatable), which was why I didn't understand what you were saying. Lesson learned. Thank you.
 
I'm glad you got there in the end. Sorry if I got a bit aggravated but it gets a bit frustrating when you provide an explicit instruction that is not followed and it was not the first time that day that it had happened. You were guilty of following your own assumptions rather than what I was posting, but I guess that we're all guilty of that sort of thing at times. The fact that the data you were adding to the ComboBox was from the DataTable does mean that they are bound. Binding creates a live relationship between the two and specifically requires the DataSource to be set.
 
Back
Top