0

I am developing a WPF user control library in C#. The library has a form where the user interacts. The form has 3 comboboxes (ComboBox1, ComboBox2 and ComboBox3). Once user selects the item in combobox1, then the combobox 2 and 3 will show items that will go with the user selection. The way I have this setup is:

xaml:

<ComboBox Grid.Column="1" Grid.ColumnSpan="2" x:Name="cmbBox_TubeType_SlabUserCtrl" Height="auto" SelectionChanged="cmbBox1_SelectedIndexChanged" x:FieldModifier="public">
         <ComboBoxItem>Item1</ComboBoxItem>
         <ComboBoxItem>Item2</ComboBoxItem>
         <ComboBoxItem>Item3</ComboBoxItem> 
</ComboBox>

C#

if (this.cmbBox1.SelectedIndex == 0)
{
    this.cmbBox2.ItemsSource = new object[] { "B01", "B02" };
    this.cmbBox3.ItemsSource = new object[] { "J01", "J22" };
}
else if (this.cmbBox1.SelectedIndex == 1)
{
    this.cmbBox2.ItemsSource = new object[] { "B21", "B22" };
    this.cmbBox3.ItemsSource = new object[] { "J21", "J32" };
}
else if (this.cmbBox1.SelectedIndex == 2)
{
    this.cmbBox2.ItemsSource = new object[] { "B31", "B32" };
    this.cmbBox3.ItemsSource = new object[] { "J21", "J32" };
}

With this setup, I then have this line which seems to give me trouble:

string cmb1TypeString = cmbBox1.SelectedItem.ToString();

When I run this cmb1TypeString is set as null. However, when I look into the class values during debug it appears it has the right value.

While trying other things, I took out the initialization of combobox items for Combobox1 from xaml. Instead I put the initialization of items right after the InitializeComponent() of class definition as follows:

this.cmbBox1.ItemsSource = new object[] { "Item1", "Item2","Item3"};

With this change the Cmb1TypeString is returned correctly as the user selected value. I am not sure why this is happening? Is there any difference between how the combobox items are treated if they are set in xaml and the code?

Help is greatly appreciated.

mm8
  • 163,881
  • 10
  • 57
  • 88
snkp
  • 43
  • 7

2 Answers2

1

I am not sure why this is happening?

The InitializeComponent() method locates a URI to the XAML file and passes it to the System.Windows.Application.LoadComponent() method that basically creates instances of the elements that you have defined in your XAML markup:

What does InitializeComponent() do, and how does it work in WPF?.

You should not access any elements before this method has returned. If you have hooked up an event handler for the SelectionChanged event of the ComboBox in the XAML, this event handler may get invoked before all ComboBox elements have been initialized.

That's why you should always check that the elements have actually been initialized before you try to access them in your SelectionChanged event handlers:

if(cmbBox1 != null && cmbBox1.IsLoaded) //<--
{
    string cmb1TypeString = cmbBox1.SelectedItem.ToString();
}
Community
  • 1
  • 1
mm8
  • 163,881
  • 10
  • 57
  • 88
  • OK. That makes sense. So if I understand your correctly, in my case when I am initializing items in xaml and since I set the SelectionChanged even also in xaml the items are never initialized. Is it a good practice to add items to combobox in the main class definition right after InitializeComponent()? This seems to fix the issue, so just curious if it is a good programming practice. – snkp Mar 28 '17 at 19:46
  • 1
    The best practice is to learn the MVVM design pattern and bind the ItemsSource of the ComboBox to an collection property of a view model: https://msdn.microsoft.com/en-us/library/hh848246.aspx – mm8 Mar 28 '17 at 20:12
0

It's not 100% clear for me what you asked but I think what you are describing is the fact that you can't ToString() a ComboBoxItem (though it should not be null either)

To test my hypothesis please use this line of code instead:

string cmb1TypeString = cmbBox1.SelectedItem.Content.ToString();

and see if anything changes.

Emad
  • 3,809
  • 3
  • 32
  • 44
  • I will try your suggestion. To clarify, later in the code I use the statement 'string cmb2TypeString = cmbBox2.SelectedItem.ToString();' and this returns the user selected value correctly. The only difference between cmbBox1 and cmbBox2/cmbBox3 is that the items in first one is initialized in xaml where as items in second and third are initialized dynamically based on user input for cmbBox1. – snkp Mar 28 '17 at 19:42