-1

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>
  • What do you want? When you say _"datacontext of my application"_, do you actually mean application like the application's root element e.g. MainWindow or do you mean the Page class that you've posted? Is the ListBox an element of this Page? You are using XPath - can I assume that the items in the ListBox are xml strings? The binding string in the constructor binds to an xml, how does the selected item comes into play? Too much guessing, because there is no clear information here. – BionicCode Mar 15 '20 at 19:33
  • I revisited your question and it still doesn't make much sense. Maybe you could explain what you are trying too achieve. I've got the feeling that your overall approach might be wrong. Do you really want to change the `DataContext` of `PageOverzicht`? This `DataContext` is the binding source for the `ListBox`. Now when changing the `DataContext` of the `ListBox` would change the `ItemsSource` too. Also when the `PageOverzicht` is loaded, you create another instance of `PageOverzicht`. Why and what are you doing with it? – BionicCode Mar 16 '20 at 12:26
  • Please can you also tell or show me what the items inside the `ListBox` are? Are they XML nodes? The code you have posted in your edit is not the one I have posted. What is the value of `ListboxFlowers.SelectedItem`? And why don't you use a simple XAML binding? – BionicCode Mar 16 '20 at 12:38
  • Okay last try to explain what I need to do here :) – Amber Akkermans Mar 16 '20 at 13:24
  • Thank you. Last try. I think I now understand you (I think). You want some sort of master/detail view. You select a color from a group of colors and want the `ListBox` to display all flower items that match the selected color? The `ListBox` will hold XML nodes that are filtered from a XML file based on the selected color? Can you please also show the `ComboBox` which holds the colors? Are these color items simple strings? – BionicCode Mar 16 '20 at 13:34
  • Okay, added to my explanation – Amber Akkermans Mar 16 '20 at 13:42
  • Wow! Now I have a totally different picture. Now I know whats going on. Now I can stop searching for my crystal ball to understand your mysterious problem :) Seriously, this is how you should have posted it initially. Let me adjust my answer. – BionicCode Mar 16 '20 at 13:54

1 Answers1

0

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>
BionicCode
  • 1
  • 4
  • 28
  • 44
  • Thanks for your answer, and my excuses for not giving you enough info. I edited my original post, hope you understand me better now – Amber Akkermans Mar 16 '20 at 12:16