zac morris Posted January 31, 2008 Report Share Posted January 31, 2008 Hi, I would like to be able to customize the legend items on a multi-series line chart. By default each legend item is labeled with the value of the 'BindingPath' for the series. For example, if 4 different series are each bound to the 'myYvalue' property of items in their respective SeriesAttributes.ItemsSource collection, then the legend will display 4 items each labeled 'myYvalue'. How do I build a template for legend items so that the 'name' (as defined by me) of each series is displayed? I've tried reproducing the following code (and datatemplate) from the RichContentPage from the AppDemo sample solution but it doesn't work: chart1.LegendBox.ItemAttributes[chart1.Series].Visibility = Visibility.Collapsed; chart1.LegendBox.ItemAttributes[chart1.AxisX].Template = (DataTemplate) FindResource("RichContentLegend"); Thanks, Zac Morris Link to comment Share on other sites More sharing options...
JuanC Posted February 2, 2008 Report Share Posted February 2, 2008 >> How do I build a template for legend items so that the 'name' (as defined by me) of each series is displayed? You have 3 options depending on the effect you want to achieve 1) If you just want to replace the default string with another string Use the SeriesAttributes.Content property, e.g. SeriesAttributes series = new SeriesAttributes();series.BindingPath = "myYvalue";series.Content = "Series Title";series.ItemsSource = enumerable; 2) If you want to keep the marker but want to display something other than a string Use the SeriesAttributes Content and ContentTemplate properties. Although Content is declared as object you should not place a visual in it because we use content in several places (LegendBox, ToolTips, DataView) and a visual can only be hosted in one parent. Instead you can assign each of your SeriesAttributes objects a CLR object in the content property and then write a template that shows some of the CLR properties, e.g. if your CLR object has ProductName and Version properties you could use a template with a couple of TextBlocks bound to these CLR properties. 3) If you want to completely control how the legend item looks Use the LegendItemAttributes.Template property, the code you tried was very close, in a multi-series chart we will show the series attributes in the legend box so your code should be chart1.LegendBox.ItemAttributes[chart1.Series].Template = (DataTemplate) FindResource("RichContentLegend"); Note that the template will be bound to a logical object that has several properties, e.g. Fill, Stroke, etc. These are the series properties so that you can allow the user a way to identify the series. It also exposes Content and ContentTemplate properties which will have the values set in option 2. Regards, JuanC Link to comment Share on other sites More sharing options...
zac morris Posted February 4, 2008 Author Report Share Posted February 4, 2008 JuanC, Thanks for the prompt and thorough reply. I will give these methods a try. Any hints on when more docs may be released?- Zac Link to comment Share on other sites More sharing options...
mgm Posted April 26, 2008 Report Share Posted April 26, 2008 Hello, I'm trying to achieve #2 above but I'm not clear how I should use Content and ContentTemplate properties of SeriesAttributes. I either get a Legend with the marker (pie slice) and no label, or a label with no marker. Please help.<cfx:Chart Name="chart1" ItemsSource="{Binding Source={StaticResource SpendByChannelProvider}}" Gallery="Pie" HorizontalAlignment="Left" Width="388.103" Grid.ColumnSpan="2" Margin="0,0,0,13" Grid.RowSpan="3"> <cfx:SeriesAttributes BindingPath="spend" Template="{StaticResource Pie2}"> <cfx:SeriesAttributes.PointLabels> <cfx:PointLabelAttributes Visibility="Visible"> <cfx:PointLabelAttributes.Template> <DataTemplate> <Label Content="{Binding Path=DataItem.Channel}" Background="Transparent" Foreground="Black" FontFamily="Calbiri" FontSize="12"/> </DataTemplate> </cfx:PointLabelAttributes.Template> </cfx:PointLabelAttributes> </cfx:SeriesAttributes.PointLabels> <cfx:SeriesAttributes.ContentTemplate> <DataTemplate> <TextBlock x:Name="BarText" Text="{Binding Path=DataItem.Channel}" HorizontalAlignment="Left" VerticalAlignment="Center"/> </DataTemplate> </cfx:SeriesAttributes.ContentTemplate> <cfx:SeriesAttributes.Content> <TextBlock x:Name="BarText" Text="{Binding Path=DataItem.Channel}" HorizontalAlignment="Left" VerticalAlignment="Center"/> </cfx:SeriesAttributes.Content> </cfx:SeriesAttributes> <cfx:Chart.LegendBox> <cfx:LegendBox> </cfx:LegendBox></cfx:Chart.LegendBox> </cfx:Chart> Link to comment Share on other sites More sharing options...
JuanC Posted April 28, 2008 Report Share Posted April 28, 2008 To achieve option #2 (displaying something more complex than a single string on the legendbox) you have to do one of the following 1) Specify the ContentTemplate in XAML but specifying the Content in code Assume you are plotting multiple series, where each series represents a product and you are plotting per-month sales of multiples products. Although the data you passed to the chart consist of sales data (Month, Amount) for each product, you might have a separate CLR objects that represent each product. If this is the case you can specify the contenttemplate in XAML and assign in code each of your series to a specific CLR object. 2) Use Crosstab When using crosstab we will transform a collection of Month, Product, Amount into a collection of Month, Amount, Product1, Product2, ... ProductN . In this case we will automatically use the first row where a product was found as the "representative" for such product. You can see a sample here Hope this helps. JuanC Link to comment Share on other sites More sharing options...
vladvm Posted April 30, 2008 Report Share Posted April 30, 2008 I tried most of the suggestions writen here, but all I can see changing is tooltip, but not the LegendBox items. I still see those as Point 1, Point 2 etc... or nothing at all. How can I change those 'Point n' in the LegendBox to something meaningful? Here is my xaml. I would like to see content of the 'Label' data element in the LegendBox. How can I do that? <XmlDataProvider x:Key="myXmlData" XPath="ChartPoints/Point"> <x:XData> <ChartPoints xmlns=""> <Point Value="5" Label="Consumer" /> <Point Value="7" Label="Energy"/> <Point Value="4" Label="Technology"/> <Point Value="3" Label="Healthcare"/> <Point Value="7" Label="Financial" /> </ChartPoints> </x:XData> </XmlDataProvider> <ChartFX:Chart x:Name="chart1" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" PointCount="5" Gallery="Pie" Background="Transparent" BorderThickness="0" ItemsSource="{Binding Source={StaticResource myXmlData}}"> <ChartFX:Chart.LegendBox> <ChartFX:LegendBox Visibility="Visible" > </ChartFX:LegendBox> </ChartFX:Chart.LegendBox> <ChartFX:SeriesAttributes BindingPath="@Value" /> </ChartFX:Chart> Thank you! Link to comment Share on other sites More sharing options...
JuanC Posted May 1, 2008 Report Share Posted May 1, 2008 The key of the misunderstanding is the concepts of series and points. In ChartFX we can handle 1 or more series, each of these series will be composed by one or more points. In a line chart, each series is represented by a different line, in a pie chart each series is represented as a pie with each point being a slice. There is also a behavior difference between bar/line/area charts and pie/doughnut/pyramid charts. In the former we default to show the series legend while the latter will display the points legend. So to customize the items displayed in a legendbox for a pie chart you have the following options 1) If you just want to replace the default string with another string Use the AxisX Labels, using your XAML as a sample you would add the following <ChartFX:Chart.AxisX> <ChartFX:Axis> <ChartFX:Axis.Labels> <ChartFX:AxisLabelAttributes BindingPath="@Label"/> </ChartFX:Axis.Labels> </ChartFX:Axis></ChartFX:Chart.AxisX>2) If you want to keep the marker but want to display something other than a string Use the SeriesAttributes ContentTemplate properties. Note that in a single chart you can use the AllSeries.ContentTemplate property. NOTE: There is a bug in current builds that will interfere with series templates in a pie chart. This approach will work in builds marked version 3043 or later. <ChartPoints xmlns=""><Point Value="5" Label="Consumer" Image="pack://siteoforigin:,,,/Img/Consumer.png" /><Point Value="7" Label="Energy" Image="pack://siteoforigin:,,,/Img/Energy.png" /><Point Value="4" Label="Technology" Image="pack://siteoforigin:,,,/Img/Technology.png" /><Point Value="3" Label="Healthcare" Image="pack://siteoforigin:,,,/Img/Healthcare.png" /><Point Value="7" Label="Financial" Image="pack://siteoforigin:,,,/Img/Financial.png" /></ChartPoints>Note that these images will be retrieved from an Img subdirectory of your app's folder. To assign the template you would add this to your XAML <ChartFX:Chart.AllSeries> <ChartFX:AllSeriesAttributes> <ChartFX:AllSeriesAttributes.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="{Binding XPath=@Image}" Width="24" Height="24"/> <TextBlock Text="{Binding XPath=@Label}" Margin="2,0" VerticalAlignment="Center"/> </StackPanel> </DataTemplate> </ChartFX:AllSeriesAttributes.ContentTemplate> </ChartFX:AllSeriesAttributes></ChartFX:Chart.AllSeries>Also note that your template will be used against the objects you pass to the chart so if you will be passing CLR objects (e.g. LinQ) you will use Bindings using Path instead of XPath 3) If you want to completely control how the legend item looks (ADVANCED) Use the LegendItemAttributes.Template property, remember that in a pie chart we show the points legend using labels stored in the X axis so your code would be chart1.LegendBox.ItemAttributes[chart1.AxisX].Template = (DataTemplate) FindResource("RichContentLegend"); The template will be bound to a logical object that has several properties, e.g. Fill, Stroke, etc. These are the visual properties for this slice so that you can allow the user a way to identify the item being labeled. It also exposes a DataItem property that returns the CLR object associated with each point. When binding to XAML we have found some issues if you try to use both XPath and Path in a Binding so we also expose a DataItemClr property that will synthesize an object based on your XML nodes. <DataTemplate x:Key="MyLegendTemplate"> <StackPanel Orientation="Horizontal" Margin="0,3"> <Ellipse Fill="{Binding Path=Fill}" Width="24" Height="24" /> <Image Source="{Binding Path=DataItemClr.@Image}" Width="24" Height="24"/> <TextBlock Text="{Binding Path=DataItemClr.@Label}" Margin="2,0" VerticalAlignment="Center"/> </StackPanel></DataTemplate> Regards, JuanC Link to comment Share on other sites More sharing options...
vladvm Posted May 2, 2008 Report Share Posted May 2, 2008 Thank you, JuanC! I have tried all three options and only the third one worked. The first one didn't compile because AxisLabelAttributes was not found in the ChartFX assembly (the version I use is 0.8.2957.30556). And moreover Axis.Labels seems to be read-only property. Is there a newer version? The second option didn't work because of the binding exception: System.Windows.Data Error: 38 : BindingExpression with XPath cannot bind to non-XML object.; XPath='@Label' BindingExpression:Path=/InnerText; DataItem='String' (HashCode=1193620881); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') Point 5 Do I need to specify DataContext explicitly? And the third option works just fine, but it doesn't support highlighting functionality when I hover over the chart. Actually I can still trigger highlighting when I hover over the legeng box items, but they do not dim as they used to (thre chart itself does dim still). How can I get this feature back? Thanks again for the quick reply and nice product! VladVM. P.S. Is it possible to get an updated version of the library? Link to comment Share on other sites More sharing options...
JuanC Posted May 2, 2008 Report Share Posted May 2, 2008 Please send a message to wpf at softwarefx dot com to request an updated build. Note that some API has been changed so updating to the newer build will force some changes in your XAML/code Regards, JuanC Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.