简体   繁体   中英

C# WinForms (.NET 3.5): ComboBox returns null reference after first selection

Note: This is a vanilla WinForms application. No WPF or WCF or anything else.

Hey people, I'm developing a WinForms (.NET 3.5) application and am stuck at a problem. I'm trying to get cities based on the selected state (both in 2 different ComboBox -es with DropDownStyle set to DropDownList ).

I have implemented this logic in the SelectedIndexChanged event handler using the SelectedValue property. The DataSource is a DataTable returned from a DB method, and SelectedValue returns an instance of DataRowView .

In the form constructor , I populate the state ComboBox and programmatically set the default state selection using SelectedIndex property; this then goes to the event handler, executes properly, and populates the city ComboBox for that state.

Now the problem comes when I change the selected state post-construction , when the form is up & running, using my mouse. This again goes to the event handler, but the SelectedValue property returns a null reference . Please help. I'm attaching the code below.

private void comboFindState_SelectedIndexChanged(object sender, EventArgs e)
        {

            DataRowView selectedState;
            int selectedStateId;
            DataTable citiesTable;

            selectedState = comboFindState.SelectedValue as DataRowView;


            if (selectedState != null) //Is true the first time around when the event is
            //triggered due to programmatic change of the index.
            //Then null afterwards, on change via mouse click.
            {
                selectedStateId = Convert.ToInt32(selectedState.Row["State Code"]);
                citiesTable = DatabaseHelper.getStateCities(selectedStateId);

                comboFindCity.DataSource = citiesTable; //Same binding for state ComboBox
                //in the form's constructor;
                comboFindCity.DisplayMember = "City"; //only here it says "State",
                comboFindCity.ValueMember = "City Code";// and here it says "State Code".

                comboFindCity.SelectedIndex = 0; //Same thing in the form's constructor for
                //setting default selected index of state ComboBox.
            }
            else
            {
                //just populates an error TextBox saying 'No Cities Found'
            }
        }

Note that all this is happening for the state ComboBox , which is already populated. The city ComboBox doesn't even enter the scope the second time, so there's no database problem.

EDIT: FYI, I have set the ValueMember property for t comboFindState from the absolute start . So that was not the reason why it didn't work. Also note that it worked properly the first time around, hence proving that the ValueMember is set properly.

Just use DataSource properly, without workarounds.
Before setting DataSource set property ValueMember to the column name which you using for getting cities

comboFindState.ValueMember = "State Code";
comboFindState.DisplayMember = "StateName"; //will be displayed in the combobox
comboFindState.DataSource = yourDataTableOfStates;

Then SelectedValue will return value of State Code as integer type (boxed in the Object type)
or null if comboFindState.SelectedIndex = -1

private void comboFindState_SelectedIndexChanged(object sender, EventArgs e)
{
    if (comboFindState.SelectedValue != null)
    {
        int selectedStateId = (int)comboFindState.SelectedValue;
        DataTable citiesTable = DatabaseHelper.getStateCities(selectedStateId);

        //Your code after getting list of the cities
    }
}

In the addition
If you will set ValueMember then you can use SelectedValueChanged event

...About comments...
how will the compiler know what 'State Code' means if the DataSource is null? If it's different, do explain
Compiler have nothing to do with this question. This happens in the runtime When you set ValueMember while DataSource is null ( before ). Then value of ValueMember will be saved and used only when you calling SelectedValue .
If ValueMember cannot be find from properties/columns of DataSource , then whole selected object will be returned, in case when DataSource is DataTable DataRowView will be returned

When you set ValueMember while DataSource is not null ( after ).
Then new value of ValueMember will be checked if properties/columns exists in the Type of DataSource . If not existed, then ArgumentException will be thrown

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM