Data Binding using XmlDataProvider and XPath

Nov 11, 2009 at 4:28 AM

Hello all; this is a fantastic library you've put together.  It's truly unrivaled in the WPF arena at the moment with respect to performance and flexibility.

I downloaded the nightly build 4394 and have been playing around with the NewMarkerSamples - specifically, the ColumnChartSample.  What I needed to do is hook up an Xml data source to the ChartPlotter instead of creating the data at random, and specify the ColumnChart's ItemsSource using XPath binding.  As such, I have created an XmlDataProvider and pointed it to my XML file:

<XmlDataProvider x:Key="sampleDataSource" Source="C:\dev\code\wpf\sample.xml" />

I then set that data source to be the root Grid's DataContext, and pointed the ColumnChart's ItemsSource to bind to an XPath.  The XAML is as below, and the sample XML is at the bottom.   But my plot comes up empty.  I would like the plot to have as many bars as there are <DataCounts> elements, for each bar to have a height determined by the <DataCounts> element, and for the tooltip to show that value.  What am I doing wrong?  I know my XPath is correct, because I can bind the data to a ListBox successfully, as follows:

 

<ListBox ItemTemplate="{DynamicResource UInt16Template}" ItemsSource="{Binding XPath=/Stats/dataDist/DataCounts}" />

where UInt16Template is a:

<DataTemplate x:Key="UInt16Template">
    <TextBlock Text="{Binding XPath=''}"/>
</DataTemplate>

I'm sure I'm missing something - sorry if this is as a result of a silly error on my part.

Bonus question, when the data get displayed: I know my min and max <DataCounts> values; they are the <Minimum> and <Maximum> elements.   Can I configure the yAxis, in XAML, to bind to those elements and go from min to max?

Thanks so much for any guidance you can offer.

E.


 

XAML:

	<Grid x:Name="rootLayout" DataContext="{Binding Source={StaticResource sampleDataSource}}"  >
		<Grid.Resources>
			<d3:BrushHSBConverter SaturationDelta="0.8" LightnessDelta="1.6" x:Key="lighterConverter"/>
			<d3:BackgroundToForegroundConverter x:Key="backToForeConv"/>
			<AlternationConverter x:Key="fillsConverter" />
		</Grid.Resources>
        
		<d3:ChartPlotter x:Name="plotter" Visible="-0.6,-1,15,4100" Grid.ColumnSpan="2" Margin="30" SnapsToDevicePixels="True">
			<d3:ColumnChart x:Name="chart" ItemsSource="{Binding XPath=/Stats/dataDist/DataCounts}">
				<d3:TemplateMarkerGenerator Custom:SelectiveScrollingGrid.SelectiveScrollingOrientation="Horizontal">
					<DataTemplate>
						<Rectangle Fill="{d3:SelfBinding (d3:PointChartBase.Index), Converter={StaticResource fillsConverter}}"
							d3:ViewportPanel.ViewportWidth="1" Margin="0,0,1,0">
							<d3:LiveToolTipService.ToolTip>
								<d3:LiveToolTip Background="{d3:SelfBinding Path=Owner.Fill, Converter={StaticResource lighterConverter}}"
									TextBlock.Foreground="{d3:SelfBinding Path=Owner.Fill, Converter={StaticResource backToForeConv}}">
									<TextBlock><Run Text="Bin:"/><InlineUIContainer>
											<TextBlock Text="{Binding Owner.(d3:PointChartBase.Index), RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type d3:LiveToolTip}, Mode=FindAncestor}}"/>
										</InlineUIContainer><Run Text=" "/><Run Text="; Count:"/><InlineUIContainer>
											<TextBlock Text="{Binding XPath=''}"/>										
										</InlineUIContainer></TextBlock>
								</d3:LiveToolTip>
							</d3:LiveToolTipService.ToolTip>
						</Rectangle>
					</DataTemplate>
				</d3:TemplateMarkerGenerator>
			</d3:ColumnChart>
		</d3:ChartPlotter>
    </Grid>


Sample XML:

 

<?xml version="1.0" encoding="utf-8"?>
<Stats xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <snr>0.68</snr>
    <dataMean>24.412920412920414</dataMean>
    <dataMedian>14</dataMedian>
    <dataDist>
        <xAxisLabel>Data Distribution</xAxisLabel>
        <yAxisLabel>Counts</yAxisLabel>
        <plotTitle>Counts Distribution</plotTitle>
        <NumPoints>14</NumPoints>
        <DataCounts>1</DataCounts>
        <DataCounts>1</DataCounts>
        <DataCounts>6</DataCounts>
        <DataCounts>101</DataCounts>
        <DataCounts>1935</DataCounts>
        <DataCounts>3187</DataCounts>
        <DataCounts>3650</DataCounts>
        <DataCounts>3342</DataCounts>
        <DataCounts>0</DataCounts>
        <DataCounts>3233</DataCounts>
        <DataCounts>1695</DataCounts>
        <DataCounts>0</DataCounts>
        <DataCounts>0</DataCounts>
        <DataCounts>456</DataCounts>
        <Minimum>0</Minimum>
        <Maximum>3650</Maximum>
    </dataDist>
</Stats>

 

 

 

Nov 12, 2009 at 3:58 PM
Edited Nov 12, 2009 at 6:41 PM

Just as a followup; storing the result of the XPath in an ObservableCollection worked just fine, but do I really need to go that extra step of converting from XML to POCO?  

 

            XmlNodeList nodelist = xd.SelectNodes("//Stats/dataDist/DataCounts");
            foreach (XmlNode node in nodelist) {
                Console.WriteLine(node.InnerText);
                double d = 0;
                if (double.TryParse(node.InnerText, out d))
                    values.Add(d);
            }

            DataContext = values; // values is ObservableCollection<double>

 

Am I doing something wrong in hooking up the data to the chart, or is there no built in capability of setting the item source straight from XPath?

<d3:ColumnChart x:Name="chart" ItemsSource="{Binding XPath=/Stats/dataDist/DataCounts}">

Thanks again for any help.
E.


Editor
Nov 13, 2009 at 5:05 PM

Hi,

 

there is one more step between ItemsSource of any our marker chart and actual drawing of markers - it is DataSource (there is such property of marker chart). A special engine tries to create a datasource from the data (of type 'object', as you probably have noticed), that comes from ItemsSource. And dataSource is actual 'source of data in marker charts. There were no such a converter that was capable of creating special dataSource from XmlElement, but now there is one. It will be available in the next changeset I'll upload, and in that changeset scenario you've described initially is working.

Best regards,

Mikhail.

Nov 13, 2009 at 7:19 PM

That's wonderful - thank you!!  Looking forward to the next installment.

 

Dec 16, 2009 at 5:03 AM

Hi Mikhail,

I just downloaded the latest code cut to see this.  Awesome.   Thanks again for including it.

E.