Okay, I'm going to try and explain my excercise now.. This is my PageOverzicht.xaml, and this code works. It gives me a dropdown with the colors of the flowers in (blue, orange, white, ...). Now the datacontext is hardcoded to find the flowers with white color. Goal: set datacontext via code behind, so that the next step can be to use selectionchanged property to select flowers with the selected color.
So now I need to set datacontext first so that it is not hardcoded to white.. Listbox consists out of xml nodes, names of plants that have the color white, using the Page_Loaded method from PageOverzicht.
<Page x:Class="Planten_BIS.PageOverzicht"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Planten_BIS"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="PageOverzicht">
<Page.Resources>
<XmlDataProvider x:Key="CatalogDataSource" XPath="catalog" Source="data/catalogus.xml"></XmlDataProvider>
<DataTemplate x:Key="listItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Name="ImageName" Visibility="Collapsed" Text="{Binding XPath=botanical, StringFormat=images/{0}.jpg}" />
<Border BorderBrush="white" BorderThickness="2" CornerRadius="10" Background="{StaticResource AchtergrondKleur}">
<Rectangle Width="100" Height="100" RadiusX="10" RadiusY="10">
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding Text, ElementName=ImageName}" />
</Rectangle.Fill>
</Rectangle>
</Border>
<StackPanel Orientation="Vertical" Margin="10" VerticalAlignment="Center">
<ListBoxItem Content="{Binding XPath=common}"/>
<ListBoxItem Content="{Binding XPath=price}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<ListBox Name="ListboxFlowers" Background="Transparent" Foreground="white" DataContext="{Binding Source={StaticResource CatalogDataSource}, XPath=color[@name\=\'White\']/plant}" ItemsSource="{Binding}" ItemTemplate="{StaticResource listItemTemplate}"></ListBox>
</Grid>
</Page>
little part from xml where data comes from:
<?xml version="1.0" encoding="ISO8859-1" ?>
<catalog>
<color name="White">
<plant>
<common>Jacob's Ladder</common>
<botanical>Polemonium caeruleum i</botanical>
<zone>Annual</zone>
<light>Shade</light>
<price>$9.26</price>
<availability>022199</availability>
<color>white</color>
<description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</description>
</plant>
Mainwindow with frame to PageOverzicht:
<Window x:Class="Planten_BIS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:Planten_BIS"
mc:Ignorable="d"
Title="Plant Catalog" Height="600" Width="800">
<Window.Resources>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource ToolBarKleur}" />
<Setter Property="BorderBrush" Value="{StaticResource RandKleur}" />
<Setter Property="Foreground" Value="{StaticResource LetterKleur}" />
<Setter Property="Height" Value="30" />
<Setter Property="Margin" Value="6" />
</Style>
<Style x:Key="comboStyle" TargetType="ComboBox">
<Setter Property="Background" Value="{StaticResource ToolBarKleur}" />
<Setter Property="BorderBrush" Value="{StaticResource RandKleur}" />
<Setter Property="Foreground" Value="{StaticResource LetterKleur}" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="30" />
<Setter Property="Margin" Value="6" />
</Style>
<XmlDataProvider x:Key="CatalogDataSource" XPath="catalog" Source="data/catalogus.xml"></XmlDataProvider>
<CollectionViewSource x:Key="cvsColors" Source="{StaticResource CatalogDataSource}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="color" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="comboItemTemplate">
<Label Content="{Binding XPath=@name}"/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ToolBar Background="{StaticResource ToolBarKleur}" DockPanel.Dock="Top">
<Button Style="{StaticResource buttonStyle}" Content="Backward"></Button>
<Button Style="{StaticResource buttonStyle}" Content="Forward"></Button>
<ComboBox Style="{StaticResource comboStyle}" SelectedIndex="0" ItemsSource="{Binding Source={StaticResource CatalogDataSource}, XPath=color}" ItemTemplate="{StaticResource comboItemTemplate}"></ComboBox>
</ToolBar>
<Frame Source="PageOverzicht.xaml" Name="frame" NavigationUIVisibility="Hidden">
<Frame.Background>
<ImageBrush ImageSource="assets/background.jpg" Stretch="UniformToFill"/>
</Frame.Background>
</Frame>
</DockPanel>
</Window>
The data source handling should be moved to a control which is the common parent of the ComboBox
and the Frame
, in this case I chose the MainWindow
.
You should add the required DependecyProperty
definitions to the MainWindow
which can be used for data binding for the ComboBox.ItemsSource
, ComboBox.SelectedItem
and the Frame.DataContext
.
For the XML handling I replaced the XMLDataProvider with an XElement
data source which allows LINQ To XML in order to comfortably filter or traverse the XML object tree in C#.
Now the ComboBox
binds to a collection of XElement
items representing XML color
nodes. The selected ComboBox
item is a single XML color
element. The descendant plant
nodes of color
are used to set the Frame.DataContext
, which is inherited to the Page.DataContext
. The ListBox
in the Page
now binds its ItemsSource
directly to the DataContext
which is the MainWindow.PlantsOfSelectedColor
property. Alternatively, e.g. if you need to set the Page.DataContext
to something different, you can let the Binding
traverse the visual tree to find the MainWindow.PlantsOfSelectedColor
using RelativeSource FindAncestor
for the Binding.RelativeSource
of ListBox.ItemsSource
.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static readonly DependencyProperty PlantColorNodesProperty = DependencyProperty.Register(
"PlantColorNodes",
typeof(IEnumerable<XElement>),
typeof(MainWindow),
new PropertyMetadata(default(IEnumerable<XElement>)));
public IEnumerable<XElement> PlantColorNodes
{
get => (IEnumerable<XElement>) GetValue(MainWindow.PlantColorNodesProperty);
set => SetValue(MainWindow.PlantColorNodesProperty, value);
}
public static readonly DependencyProperty SelectedPlantColorNodeProperty = DependencyProperty.Register(
"SelectedPlantColorNode",
typeof(XElement),
typeof(MainWindow),
new PropertyMetadata(default(XElement), OnSelectedPlantColorNodeChanged));
public XElement SelectedPlantColorNode
{
get => (XElement) GetValue(MainWindow.SelectedPlantColorNodeProperty);
set => SetValue(MainWindow.SelectedPlantColorNodeProperty, value);
}
public static readonly DependencyProperty PlantsOfSelectedColorProperty = DependencyProperty.Register(
"PlantsOfSelectedColor",
typeof(IEnumerable<XElement>),
typeof(MainWindow),
new PropertyMetadata(default(IEnumerable<XElement>)));
public IEnumerable<XElement> PlantsOfSelectedColor
{
get => (IEnumerable<XElement>) GetValue(MainWindow.PlantsOfSelectedColorProperty);
set => SetValue(MainWindow.PlantsOfSelectedColorProperty, value);
}
public MainWindow()
{
InitializeComponent();
// Open XML an collect all 'color' nodes
this.PlantColorNodes = XElement.Load("data/catalogus.xml").Elements("color");
}
private static void OnSelectedPlantColorNodeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var colorNode = e.NewValue as XElement;
// Get the 'plant' child nodes of the selected 'color' node
(d as MainWindow).PlantsOfSelectedColor = colorNode.Elements();
}
}
MainWindow.xaml
<Window>
<DockPanel LastChildFill="True">
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=MainWindow}, Path=PlantColorNodes}"
SelectedItem="{Binding RelativeSource={RelativeSource AncestorType=MainWindow}, Path=SelectedPlantColorNode}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Attribute[name].Value}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox>
<Frame DatContext="{Binding RelativeSource={RelativeSource AncestorType=MainWindow}, Path=PlantsOfSelectedColor}"
Source="PageOverzicht.xaml" />
</DockPanel>
</Window>
PageOverzicht.xaml
<Page>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Element[botanical].Value}" />
<TextBlock Text="{Binding Element[common].Value}"/>
<TextBlock Text="{Binding Element[price].Value}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>