views:

52

answers:

1

I have a ComboBox that needs to depend on the value of another ComboBox. This part already works, with the dependent ComboBox refreshing when a new value is chosen in the independent ComboBox:

<!-- Independent -->
<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="2"
          x:Name="cbo_product" VerticalAlignment="Center" Width="120"
          ItemsSource="{Binding Source={StaticResource productsXml}}"
          DisplayMemberPath="@name" SelectedValuePath="@name"
          SelectionChanged="cbo_product_SelectionChanged"
          SelectedValue="{Binding Path=Product}" />

<!-- Dependent -->
<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="2"
          x:Name="cbo_component" VerticalAlignment="Center" Width="201"
          DataContext="{Binding SelectedItem, ElementName=cbo_product}"
          ItemsSource="{Binding XPath=Components/Component}"
          DisplayMemberPath="@name" SelectedValuePath="@name"
          SelectedValue="{Binding Path=Component}"
          SelectionChanged="cbo_component_SelectionChanged" />

In the C# class behind this, I have:

public MyUserControlConstructor()
{
    MyViewModelInstance= new MyViewModel();
    DataContext = MyViewModelInstance;
}

And in MyViewModel, I have:

public string Component
{
    get { return _component; }
    set
    {
        if (value == _component)
        {
            return;
        }
        _component = value;
        onPropertyChanged(PropertyNames.Component);
    }
}

private void onPropertyChanged(PropertyNames fieldName)
{
    if (null == PropertyChanged)
    {
        return;
    }
    string propertyName = Enum.GetName(typeof(PropertyNames), fieldName);
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

When I change the dependent ComboBox (Component), it shows up with the new value in my app, of course. However, when I hit a button that causes the value of the Component property to be displayed, it is always the initial value, and not the value I just chose in the ComboBox. I think there must be an error in my XAML. For the C#, I tried to follow a combination of this and this guide. How do I tie my dependent ComboBox to XML values nested in the SelectedItem of the independent ComboBox, but still update the Component property in my class?

Edit: my suspicion is that things are wonky because I set the DataContext for the dependent ComboBox in two places: first in the constructor in C#, to my view model, and second in the XAML, to DataContext="{Binding SelectedItem, ElementName=cbo_product}".

Edit: I had been setting initial values in the constructor to my view model class. When I take out the initial value for the Component property, then even after I change the selected value in the dependent ComboBox, I still get no value from the Component property. This pretty much just rehashes what I already knew: the dependent ComboBox is tied to the independent ComboBox (it gets its data from the independent ComboBox, that is), but not to the Component property.

Edit: by request, here's a sample of my XML:

<Products xmlns="">
  <Product name="Awesomeness">
    <Components>
      <Component name="Component of Glory"/>
      <Component name="Component of Doom"/>
    </Components>
  </Product>
</Products>

Edit: I'm guessing a MultiBinding would be of use, after looking at this and this.

Edit: it seems like I should be able to get the dependent ComboBox to work without setting DataContext, just by using ItemsSource:

<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="2"
                      x:Name="cbo_component" VerticalAlignment="Center" Width="201"
                      ItemsSource="{Binding ElementName=cbo_product, Path=SelectedItem,
                          XPath=Components/Component}"
                      DisplayMemberPath="@name" SelectedValuePath="@name"
                      SelectedValue="{Binding Path=Component}"
                      SelectionChanged="cbo_component_SelectionChanged"/>

However, this doesn't work: the dependent ComboBox is empty, instead of showing all the Component names.

A: 

The way I found of getting around this involves setting the ItemsSource in C# instead of XAML, which I would prefer not to do. However, it works, and after a day and a half of banging on this, it's the best I came up with.

In XAML:

<!-- Independent -->
<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="2"
          x:Name="cbo_product" VerticalAlignment="Center" Width="120"
          ItemsSource="{Binding Source={StaticResource productsXml}}"
          DisplayMemberPath="@name" SelectedValuePath="@name"
          SelectionChanged="cbo_product_SelectionChanged"
          SelectedItem="{Binding Path=ProductNode}"
          SelectedValue="{Binding Path=Product}" />

<!-- Dependent -->
<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="2"
          x:Name="cbo_component" VerticalAlignment="Center" Width="201"
          DisplayMemberPath="@name" SelectedValuePath="@name"
          SelectedValue="{Binding Path=Component, Mode=TwoWay}"
          SelectionChanged="cbo_component_SelectionChanged"/>

In C#, the event handler for when the independent ComboBox changes:

private void cbo_product_SelectionChanged(object sender,
    SelectionChangedEventArgs e)
{
    // Set ItemsSource of dependent ComboBox
    cbo_component.ItemsSource = getChildNodesFromComboBox(
        sender as ComboBox, "Components/Component"
    );
    cbo_component.SelectedIndex = 0;
}

// Helper method to do XPath query and get child nodes from selected value of
// independent ComboBox
private XmlNodeList getChildNodesFromComboBox(ComboBox comboBox,
    string xpath)
{
    if (null == comboBox)
    {
        return null;
    }
    var xml = comboBox.SelectedItem as XmlElement;
    if (null == xml)
    {
        return null;
    }
    return xml.SelectNodes(xpath);
}

Now the Component property in my view model class, to which my dependent ComboBox is bound in XAML, gets populated with the value selected in the dependent ComboBox because I didn't have to change the DataContext of the dependent ComboBox.

Sarah Vessels