locked
XPath Confusion RRS feed

  • Question

  • I am ultimately trying to filter XML data in a list.  Everything I have read talks about adding XPath=""... Like this...

     

    <XmlDataProvider x:Key="InventoryData" XPath="Inventory/Books">
    

     

    Well I used the Blend UI to add my XML's and to bind the data.  My xaml file doesn't say anything about "XmlDataProvider".  When I try to add XPath it says "Chrissy you don't know what the hell you are doing!  Stop That!"

     

    Here is my XML file...

     

    <?xml version="1.0" encoding="UTF-8"?>
    <dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2011-06-04T14:21:45">
    <Product>
    <ID>101</ID>
    <Name>Old Book</Name>
    <Price>10</Price>
    </Product>
    <Product>
    <ID>105</ID>
    <Name>New Book</Name>
    <Price>20</Price>
    </Product>
    <Product>
    <ID>110</ID>
    <Name>Video Tape</Name>
    <Price>25</Price>
    </Product>
    <Product>
    <ID>112</ID>
    <Name>Video Game</Name>
    <Price>30</Price>
    </Product>
    <Product>
    <ID>130</ID>
    <Name>Candy Bar</Name>
    <Price>5</Price>
    </Product>
    </dataroot>
    

     

     

    and here is my XAML file...

     

    <Window
    	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" mc:Ignorable="d"
    	x:Class="WpfApplication2.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="300" Height="300">
    
    	<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ProductSampleDataSource}}" >
    		<ListView x:Name="myListView" HorizontalAlignment="Center" Width="250" ItemsSource="{Binding ProductCollection}" SelectedIndex="0" Margin="0,15,0,115" Background="#3FFFFFFF" Foreground="Black">
    			<ListView.View>
    				<GridView>
    					<GridViewColumn Width="50" Header="ID" DisplayMemberBinding="{Binding ID}" />
    					<GridViewColumn Width="100" Header="Name" DisplayMemberBinding="{Binding Name}" />
    					<GridViewColumn Width="50" Header="Cost" DisplayMemberBinding="{Binding Price}" />
    				</GridView>
    			</ListView.View>
    		</ListView>
    		<Grid x:Name="SelectedItemGrid" Margin="17,0,17,35.48" Background="#3FFFFFFF" Height="75.52" VerticalAlignment="Bottom" DataContext="{Binding SelectedItem, ElementName=myListView}" d:DataContext="{Binding ProductCollection[0]}">
    			<Label x:Name="label1" Content="Product ID:" HorizontalAlignment="Left" Width="90" Height="25" VerticalAlignment="Top" d:LayoutOverrides="VerticalAlignment, Height" Foreground="Black"/>
    			<Label x:Name="label2" Content="Product Name:" HorizontalAlignment="Left" Margin="0,25,0,0" VerticalAlignment="Top" Width="90" Height="25" Foreground="Black"/>
    			<Label x:Name="label3" Content="Product Price:" HorizontalAlignment="Left" Margin="0,50,0,0" VerticalAlignment="Top" Width="90" Height="25" Foreground="Black"/>
    			<TextBlock x:Name="prodID" Text="{Binding ID}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="104" Margin="146,5,0,0"/>
    			<TextBlock x:Name="prodName" Text="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="104" Margin="146,30,0,0"/>
    			<TextBlock x:Name="prodPrice" Text="{Binding Price}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="104" Margin="146,55,0,0"/>
    		</Grid>
    		<Grid x:Name="FilterGrid" Height="27.48" Margin="8,0,8,8" VerticalAlignment="Bottom" Background="Blue">
    			<TextBox x:Name="filterTextBox" Margin="0,2,2,2" TextWrapping="Wrap" HorizontalAlignment="Right" Width="118">
    				<TextBox.BorderBrush>
    					<LinearGradientBrush EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
    						<GradientStop Color="#FFABADB3" Offset="0.05"/>
    						<GradientStop Color="#FFE2E3EA" Offset="0.07"/>
    						<GradientStop Color="#FF0059B2" Offset="1"/>
    					</LinearGradientBrush>
    				</TextBox.BorderBrush>
    			</TextBox>
    			<Label x:Name="filterLabel" Content="Filter by Name" Margin="0,0,122,0" Foreground="White" FontWeight="Bold"/>
    		</Grid>
    	</Grid>
    </Window>

     

     

    and there is nothing in the code-behind...

     

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    
    namespace WpfApplication2
    {
    	public partial class MainWindow : Window
    	{
    		public MainWindow()
    		{
    			this.InitializeComponent();
    		}
    	}
    }
    

     

    If I understand what I have read in posts here... I need to bind my "filterTextBox" to "myListView", but somehow XPaths come into play which my Blend says "Nope!"

     

    Would someone by so kind as to tell me what I need to do to filter my XML list.

     

    Thanks!

     

    ~Christine

     


    Sunday, June 5, 2011 7:59 PM

Answers

  • Well it turns out I needed to add my XML file as a data source and not sample data.

     

    So I started a new project and added it as a data source and not sample data.

     

    I added a list box.

    <Window.Resources>
    		<XmlDataProvider x:Key="ProductData" Source="C:\Users\Christine\Documents\csStuffLearning\WpfApplication2\WpfApplication2\Product.xml" XPath="dataroot/Product/ID" d:IsDataSource="True"/>
    		<DataTemplate x:Key="DataTemplate1">
    			<StackPanel Orientation="Horizontal" Width="592.56">
    				<TextBlock Text="{Binding XPath=ID}" Margin="20,0,0,0"/>
    				<TextBlock Text="{Binding XPath=Name}" Margin="20,0,0,0"/>
    				<TextBlock Text="{Binding XPath=Price}" Margin="20,0,0,0"/>
    			</StackPanel>
    		</DataTemplate>
    	</Window.Resources>
    
    	<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ProductData}}">
    		<ListBox ItemTemplate="{DynamicResource DataTemplate1}" ItemsSource="{Binding XPath=/dataroot/Product}" Margin="8,8,8,0" Height="86" VerticalAlignment="Top"/>
    	</Grid>
    </Window>

    When I change the XPath to XPath="" or XPath="dataroot/Product" or XPath="dataroot/Product/ID" the full list shows.

     

    When I try to do something like one of these, nothing will show in the list...

    XPath="Book[1]" will return the first book element ("XML in Action"). Note that XPath indexes are based on 1, not 0.

    XPath="Book[@*]" will return all book elements with any attributes.

    XPath="Book[last()-1]" will return the second to last book element ("Introducing Microsoft .NET").

    XPath="*[position()>3]" will return all of the book elements except for the first 3.

     

    I got those examples from this page: http://msdn.microsoft.com/en-us/library/system.windows.data.xmldataprovider.aspx

     

    So, any suggestions on how I can filter my list?  And really I'd like to know how to pass a value from a textbox into the XPath for the filter.

     

    Hmmm.... I confused myself there....  

    1.  Info put into text box.

    2.  Info from text box passed to the XPath

    3.  List filtered as a result.

    4.  Chrissy happy.

     

    :)

     

    Any help would be greatly appreciated.

     

    ~Christine

     

     

    Sunday, June 5, 2011 9:27 PM
  • Hello Christine, maybe you could try to use multibinding combined with a value converter. here is a link: http://www.google.de/gwt/x?q=wpf+xmldataprovider+databinding+converterparameter&ei=B1LsTfCQCoaN8gOngcBu&ved=0CA8QFjAC&hl=de&source=m&rd=1&u=http://michlg.wordpress.com/2009/10/13/wpf-bind-value-to-binding-converterparameter/ Could you tell me, why don't you use linq to xml to filter your data? Additionaly I would like to point to the performance aspect. Binding to xml is less performant than binding to clr objects. So if possible, try to bind to clr objects.
    • Marked as answer by Christine L. _ Tuesday, February 28, 2012 8:36 PM
    Monday, June 6, 2011 4:44 AM

All replies

  • Well it turns out I needed to add my XML file as a data source and not sample data.

     

    So I started a new project and added it as a data source and not sample data.

     

    I added a list box.

    <Window.Resources>
    		<XmlDataProvider x:Key="ProductData" Source="C:\Users\Christine\Documents\csStuffLearning\WpfApplication2\WpfApplication2\Product.xml" XPath="dataroot/Product/ID" d:IsDataSource="True"/>
    		<DataTemplate x:Key="DataTemplate1">
    			<StackPanel Orientation="Horizontal" Width="592.56">
    				<TextBlock Text="{Binding XPath=ID}" Margin="20,0,0,0"/>
    				<TextBlock Text="{Binding XPath=Name}" Margin="20,0,0,0"/>
    				<TextBlock Text="{Binding XPath=Price}" Margin="20,0,0,0"/>
    			</StackPanel>
    		</DataTemplate>
    	</Window.Resources>
    
    	<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ProductData}}">
    		<ListBox ItemTemplate="{DynamicResource DataTemplate1}" ItemsSource="{Binding XPath=/dataroot/Product}" Margin="8,8,8,0" Height="86" VerticalAlignment="Top"/>
    	</Grid>
    </Window>

    When I change the XPath to XPath="" or XPath="dataroot/Product" or XPath="dataroot/Product/ID" the full list shows.

     

    When I try to do something like one of these, nothing will show in the list...

    XPath="Book[1]" will return the first book element ("XML in Action"). Note that XPath indexes are based on 1, not 0.

    XPath="Book[@*]" will return all book elements with any attributes.

    XPath="Book[last()-1]" will return the second to last book element ("Introducing Microsoft .NET").

    XPath="*[position()>3]" will return all of the book elements except for the first 3.

     

    I got those examples from this page: http://msdn.microsoft.com/en-us/library/system.windows.data.xmldataprovider.aspx

     

    So, any suggestions on how I can filter my list?  And really I'd like to know how to pass a value from a textbox into the XPath for the filter.

     

    Hmmm.... I confused myself there....  

    1.  Info put into text box.

    2.  Info from text box passed to the XPath

    3.  List filtered as a result.

    4.  Chrissy happy.

     

    :)

     

    Any help would be greatly appreciated.

     

    ~Christine

     

     

    Sunday, June 5, 2011 9:27 PM
  • Hello Christine, maybe you could try to use multibinding combined with a value converter. here is a link: http://www.google.de/gwt/x?q=wpf+xmldataprovider+databinding+converterparameter&ei=B1LsTfCQCoaN8gOngcBu&ved=0CA8QFjAC&hl=de&source=m&rd=1&u=http://michlg.wordpress.com/2009/10/13/wpf-bind-value-to-binding-converterparameter/ Could you tell me, why don't you use linq to xml to filter your data? Additionaly I would like to point to the performance aspect. Binding to xml is less performant than binding to clr objects. So if possible, try to bind to clr objects.
    • Marked as answer by Christine L. _ Tuesday, February 28, 2012 8:36 PM
    Monday, June 6, 2011 4:44 AM
  • Thank you very much for your response.  I am sure for anyone else that may very well be the answer, but I read it and it all looks Greek to me.  It is just a bit to complicated for me.

     

    One of the appeals of Blend, for me, was that so much could be achieved in the Blend UI, which was great for someone that knew very little about C#.  Everything I know about C# I have pretty much learned here while learning Blend.

     

    While I am showing a very simple little project that explains what I am trying to do, the project I am actually creating involes 20 plus tables of data from an Access database.  Each table contains over 500 records with the largest containing over 4,000.  I started that Access database in 2002 and it has evolved each year.  Converting the tables to XML took no time at all and it seems like the perfect solution for me.  Truth be told, I'm a bit lazy and didn't wont to have to type all that information in.

     

    My project is just about ready to go and works perfectly for what I am trying to do.  I am simply missing one key ingredient.... filtering the XML data in a listbox.  I had read a reply that Chuck Hayes had given to someone who was asking a similar question and while I didn't quite understand his answer, it left me with the idea that what I am trying to accomplish could be achieved from within the Blend UI. 

     

    But then again I'm not all that bright ya know.  So I could be mistaken.

     

    ~Christine

    Monday, June 6, 2011 3:30 PM