Sometimes the size available to a chart imposes a restriction where the legend just takes too much space. In this post we will discuss a couple of possibilities on how to approach this problem
Style your title to mimic a legend
In Chart FX for WPF titles are fully stylable and although typically titles are just strings, you can in fact use any WPF visuals in the title. The problem with this approach is that you would have to code too much information into the title, for example the number of series, colors, etc. which makes this scenario not practical. Also note that things like highlight would not work.
Show the legend underneath the title
Just removing the legend box border and docking the legend box to the top might be sufficient in many scenarios
<cfx:Chart.Titles>
<cfx:Title>Sales in 1998</cfx:Title>
</cfx:Chart.Titles>
<cfx:Chart.LegendBox>
<cfx:LegendBox cfx:Chart.DockBorder="None" DockPanel.Dock="Top" />
</cfx:Chart.LegendBox>
Note that in our default style (Glass) the main title is drawn larger and outside the plotting area space, if you would rather have them both together you can change the target panel of the legend box, note that in older builds we did not support a way to specify the index so you might need an updated build if this does not generate the expected results
<cfx:Chart.LegendBox>
<cfx:LegendBox cfx:Chart.DockBorder="None" DockPanel.Dock="Top"
cfx:Chart.TargetPanel="Titles-0" />
</cfx:Chart.LegendBox>
Combine the title and legend in one line
If the number of series is small we might be able to combine the title text and legend box in one line. To do this we will have to style the legend box and items so it will be a little more involved, hopefully the result will be worthwhile.
<Style x:Key="LegendTitleStyle" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal" IsItemsHost="True"
VerticalAlignment="Top" />
<TextBlock VerticalAlignment="Top" Text="{Binding Path=Tag}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="LegendTitleItem">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<cfxConverters:BoolToVisibilityConverter x:Key="BoolToVisibility"/>
</StackPanel.Resources>
<StackPanel VerticalAlignment="Top" x:Name="textAndLine">
<Border Background="Transparent">
<ContentControl IsHitTestVisible="false" Content="{Binding Path=Content}"
ContentTemplate="{Binding Path=ContentTemplate}"
Foreground="{Binding Path=Foreground}"
FontFamily="{Binding Path=FontFamily}"
FontSize="{Binding Path=FontSize}"
FontStyle="{Binding Path=FontStyle}"
FontWeight="{Binding Path=FontWeight}"/>
</Border>
<Rectangle Fill="{Binding Path=Stroke}" Height="3"/>
</StackPanel>
<TextBlock Text=" "/>
<TextBlock Text="Vs " IsHitTestVisible="false"
Visibility="{Binding Path=LastInGroup,
Converter={StaticResource BoolToVisibility},
ConverterParameter=false}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Dimmed}">
<DataTrigger.Value>
<sys:Boolean>True</sys:Boolean>
</DataTrigger.Value>
<Setter Property="Opacity" Value="0.25" TargetName="textAndLine" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate> <cfx:Chart.LegendBox>
<cfx:LegendBox cfx:Chart.DockBorder="None" DockPanel.Dock="Top"
Tag="Sales in 1998"
ContainerStyle="{StaticResource LegendTitleStyle}">
<cfx:LegendBox.ItemAttributes>
<cfx:LegendItemAttributes cfx:LegendItemAttributes.LegendItemType="Series"
Template="{StaticResource LegendTitleItem}"/>
</cfx:LegendBox.ItemAttributes>
</cfx:LegendBox>
</cfx:Chart.LegendBox>
Key points from the XAML
- In LegendTitleStyle we set a template that has a horizontal stack panel (legend items) + the legend Tag, this allows to reuse this style as all we have to change is the LegendBox tag property.
- In LegendTitleItem we are showing the legend content with a line under it that uses the series stroke instead of fill, this makes the line a little darker.
- To hide the separator text (Vs) we used a ChartFX converter because it allows us to set Visibility to Collapsed when the bool property (LastInGroup) is true by setting ConverterParameter to false. The built-in BooleanToVisibilityConverter only seems to convert True to Visible.
- By using a ContentControl instead of a TextBlock our template should work even if you use Series.ContentTemplate to a more complex visual.
Please note that the legend box can show much more than just the series as it can display information about conditional attributes, axis sections, axis custom gridlines, etc. but in simple scenarios this approach generates a simpler chart while still providing contextual information to your users.
JuanC