WPF, linking together two XML data sources in cascading ComboBoxes
I have XML in the following format:
<Products>
<Product name="MyProduct1">
<Components>
<Component name="MyComponent1">
<Teams>
<Team id="1"/>
<Team id="4"/>
</Teams>
</Component>
</Components>
</Product>
<开发者_C百科/Products>
This is stored in an external XML file that is included via an XmlDataProvider
in my XAML:
<XmlDataProvider Source="Products.xml"
XPath="Products/Product"
x:Key="productsXml"/>
You'll see that the Team
nodes have only an id
attribute; this links them to other XML that is embedded directly in my XAML:
<XmlDataProvider x:Key="teamsXml" XPath="Teams/Team">
<x:XData>
<Teams xmlns="">
<Team name="Team A" id="1"/>
<Team name="Team B" id="2"/>
<Team name="Team C" id="3"/>
<Team name="Team D" id="4"/>
</Teams>
</x:XData>
</XmlDataProvider>
I have the following ComboBox in my XAML:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="133,217,0,0"
Name="cbo_team" VerticalAlignment="Top" Width="148"
DataContext="{Binding ElementName=cbo_component, Path=SelectedItem}"
ItemsSource="{Binding XPath=Teams/Team}"
SelectedIndex="0" />
This ComboBox shows a list of Teams associated with the currently selected Component. I need to keep DataContext
and ItemsSource
the same here so that only the related Teams are shown, and not all available Teams. However, I don't want to show the Team id
attribute in the ComboBox, I want to show the name
attribute as it is defined in teamsXml
, e.g., Team A. How can I use a DataTemplate
and somehow get the Team name from teamsXml
when I have the Team id
from productsXml
? I also want the value of the ComboBox to be the name
attribute.
Edit:
I'm wondering if something like this is a step in the right direction:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="133,217,0,0"
Name="cbo_team" VerticalAlignment="Top" Width="148"
DataContext="{Binding ElementName=cbo_component, Path=SelectedItem}"
ItemsSource="{Binding XPath=Teams/Team}"
SelectedIndex="0">
<ComboBox.DisplayMemberPath>
<Binding Source="{StaticResource teamsXml}"
XPath="???"/> <!-- Need to select the @name attribute of the node
whose @id attribute is the same value as the
current selected item in this ComboBox -->
</ComboBox.DisplayMemberPath>
</ComboBox>
I'd use Linq to xml and fill a CollectionViewSource. Then bind to that rather than xmlDataProvider.
Once again, this guy's article helped me out. I moved my Teams
XML into my Products.xml file, so I have the following format:
<Products>
<Product name="MyProduct1">
<Components>
<Component name="MyComponent1">
<Teams>
<Team id="1"/>
<Team id="4"/>
</Teams>
</Component>
</Components>
</Product>
<Teams>
<Team name="Team A" id="1"/>
<Team name="Team B" id="2"/>
<Team name="Team C" id="3"/>
<Team name="Team D" id="4"/>
</Teams>
</Products>
Then, I did the following for my ComboBox in XAML:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="133,218,0,0"
Name="cbo_team" VerticalAlignment="Top" Width="148"
DataContext="{Binding ElementName=cbo_component, Path=SelectedItem}">
<ComboBox.ItemsSource>
<Binding XPath="Teams/Team/@id"
Converter="{StaticResource xmlConverter}">
<Binding.ConverterParameter>
<local:XmlConverterParameter
XPathTemplate="/Products/Teams/Team[{0}]"
XPathCondition="@id='{0}'" />
</Binding.ConverterParameter>
</Binding>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=@name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I had to include the following in my <Window.Resources>
in XAML:
<local:XmlConverter x:Key="xmlConverter"/>
And, following his tutorial, I created two C# classes: XmlConverter
and XmlConverterParameter
. Now my ComboBox converts a team id
to a name
and displays the name
, so my XML is fairly DRY because the team names are only defined in one place.
精彩评论