Reputation: 499
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 tcomboFindState
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.
Upvotes: 0
Views: 559
Reputation: 32445
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
Upvotes: 2