Styling a WPF application so that it looks similar to Expression Blend seems to be a common scenario, you can even download a couple of open-source projects from Codeplex called “WPF Futures” and “WPF Themes” that include Expression Dark as one of several styles you can use in your WPF applications.
If you use one of these projects, all the common controls will be automatically styled (ListBox, Label, Slider, etc.) but it will not affect how your charts look, so you will get something like this
The first thing we can do to make our chart look integrated with the application is to change the brushes used for all the elements (bars, background, titles, point labels, etc.), in order to do this we will add to our app.xaml a style targeting all charts as follows
xmlns:cfx="http://schemas.softwarefx.com/chartfx/wpf/80"
xmlns:cfxMotifs=http://schemas.softwarefx.com/chartfx/wpf/80/motifs
<Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
<Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
<Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
</Style>
The first setter will switch the chart template from the default (Glass) to a simpler template (Simple), this removes the reflection at the bottom as well as the 3D-like floor. The second setter to change the chart’s palette references a resource in our app.xaml that will hold the palette and will look like this
<cfx:Palette x:Key="PaletteExpressionDark">
<cfx:Palette.SeriesFill>
<Brush>#5372B0</Brush>
<Brush>#FFEC35</Brush>
…
</cfx:Palette.SeriesFill>
<cfx:Palette.SeriesStroke>
<Brush>#324468</Brush>
<Brush>#897E1C</Brush>
…
</cfx:Palette.SeriesStroke>
<cfx:Palette.SeriesForegroundInside>
<Brush>#FF385516</Brush>
<Brush>#FF575113</Brush>
…
</cfx:Palette.SeriesForegroundInside>
<cfx:Palette.Foreground>#FFFFFFFF</cfx:Palette.Foreground>
<cfx:Palette.Background>#FF333333</cfx:Palette.Background>
<cfx:Palette.Border>…</cfx:Palette.Border>
<cfx:Palette.PointLabelForeground>#FFFFFFFF</cfx:Palette.PointLabelForeground>
<cfx:Palette.PointLabelForegroundInside>
#FFFFFFFF
</cfx:Palette.PointLabelForegroundInside>
<cfx:Palette.Axis>#BDBDBD</cfx:Palette.Axis>
<cfx:Palette.AxisGridLines>#FF8B8B8B</cfx:Palette.AxisGridLines>
…
<cfx:Palette.PlotArea>#40595959</cfx:Palette.PlotArea>
<cfx:Palette.MainArea>Transparent</cfx:Palette.MainArea>
<cfx:Palette.Title>#DFDFDF</cfx:Palette.Title>
<cfx:Palette.LegendForeground>#DFDFDF</cfx:Palette.LegendForeground>
<cfx:Palette.DataViewBackground>#40595959</cfx:Palette.DataViewBackground>
…
<cfx:Palette.ToolTipForeground>#EEEEEE</cfx:Palette.ToolTipForeground>
<cfx:Palette.View3DAmbientLight>#808080</cfx:Palette.View3DAmbientLight>
<cfx:Palette.ThumbStroke>#FFD1D1D1</cfx:Palette.ThumbStroke>
<cfx:Palette.SelectionFill>#8C00AEFF</cfx:Palette.SelectionFill>
…
</cfx:Palette>
Note that this palette has been trimmed so there are several entries missing, you can check the attached XAML for a complete palette, I wanted to highlight the following
- You can supply as many brushes as desired for the chart series, if there are more series we will loop through this list
- You can optionally supply brushes used for the borders of the markers, if you don’t we will use a lightly darker version of the series brushes
- SeriesForegroundInside will be used when we know the point label is drawn inside the marker while the single PointLabelForeground will be used when the point is drawn on the plot area.
- If you want, you can instead provide a single PointLabelForegroundInside and remove the SeriesForegroundInside
- There are additional entries for the DataView, Legend, ToolTip, Titles and 3D
The combination of a simpler style and using the same colors/gradients makes a big change but there are still several things we can improve, note that the border has not changed, when we designed Chart FX for WPF we wanted to be able to separate the styling of the different chart elements so changing the chart template did not result in the border being changed. This also means that in your chart you can modify the border appearance without worrying about the other elements in the chart.
<cfx:ControlTemplateBorder x:Key="BorderDark">
<cfx:ControlTemplateBorder.Template>
<ControlTemplate TargetType="{x:Type cfx:ChartBorder}">
<ControlTemplate.Resources>
<Thickness x:Key="cfxBorderThickness">1</Thickness>
<Style x:Key="cfxInternalBorderStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border CornerRadius="2"
BorderBrush="{Binding Path=Palette.AlternateBorder}"
RelativeSource={RelativeSource TemplatedParent},
Background="{TemplateBinding Background}" BorderThickness="1">
<ContentPresenter Margin="{TemplateBinding Padding}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<CornerRadius x:Key="cfxCornerRadius">2</CornerRadius>
</ControlTemplate.Resources>
<Border cfx:Chart.PanelName="BorderChild"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}" CornerRadius="2"
BorderThickness="{TemplateBinding BorderThickness}" />
</ControlTemplate>
</cfx:ControlTemplateBorder.Template>
</cfx:ControlTemplateBorder>
<Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
<Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
<Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
<Setter Property="Border" Value="{StaticResource BorderDark}"/>
</Style>
We are now setting the Border property using a ControlTemplateBorder class, if you ignore the resources for a moment it is just a single Border with some template bindings but the PanelName=”BorderChild” is very important, we will find the element with this value for the Chart.PanelName attached property and we will add inside of it the other visuals that generate the chart.
- If we find a resource named cfxBorderThickness it will be used as a default border thickness unless you set the Chart.BorderThickness property
- The cfxInternalBorderStyle will be used for the borders of the legend box and dataview
- If the element marked as “BorderChild” has some roundness you must set the cfxCornerRadius appropriately
Additionally you will notice that we have a default scrollbar style that does not match with the one used in the listbox, for this we will have to modify another property called MergeResources that expects a ResourceDictionary (we did not use a built-in WPF feature that does this because it causes memory leaks)
<ResourceDictionary x:Key="ResourcesDark">
<Style x:Key="ThumbStyle" TargetType="{x:Type Thumb}" BasedOn="{x:Null}">
<Setter Property="Template">
<Setter.Value>…</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>…</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Template">
<Setter.Value>…</Setter.Value>
</Setter>
</Style>
</ResourceDictionary> <Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
<Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
<Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
<Setter Property="Border" Value="{StaticResource BorderDark}"/>
<Setter Property="MergeResources" Value="{StaticResource ResourcesDark}"/>
</Style>
Again we removed most of the xaml but this is just a copy of how a scrollbar is styled for expression dark. We are now getting really close as you can see in the following pictures
Depending on your application you can actually stop the styling here but there is still some of the glass showing on the markers, if you decide you want simpler visuals you can add the following
<ResourceDictionary x:Key="GalleryDark">
<DataTemplate x:Key="Bar">
<DataTemplate.Resources>
<sys:Double x:Key="cfxDefStrokeThickness">1</sys:Double>
<DataTemplate x:Key="cfxLastStack">…</DataTemplate>
<DataTemplate x:Key="cfxMiddleStack">…</DataTemplate>
<DataTemplate x:Key="cfxFirstStack">…</DataTemplate>
</DataTemplate.Resources>
<Border x:Name="bar" CornerRadius="2,2,0,0"
Width="{Binding Path=Width}" Height="{Binding Path=Height}"
Background="{Binding Path=Fill}" BorderBrush="{Binding Path=Stroke}"
BorderThickness="{Binding Path=StrokeThickness}"
Opacity="{Binding Path=Opacity}"
RenderTransform="{Binding Path=Transform}" />
<DataTemplate.Triggers>…</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="Line">
<DataTemplate.Resources>
<sys:Double x:Key="cfxDefStrokeThickness">3</sys:Double>
<sys:Double x:Key="cfxDefMarkerSize">10</sys:Double>
<sys:String x:Key="pointsCategory">lineShadow</sys:String>
</DataTemplate.Resources>
<Canvas Opacity="{Binding Path=Opacity}">
<Polyline Visibility="{Binding Path=EffectsVisibility}" x:Name="lineShadow"
Points="{Binding Path=Points}"
Canvas.Top="{Binding Path=StrokeThickness,
Converter={StaticResource multiplyConverter},
ConverterParameter=1.50}"
Stroke="#FF000000" StrokeThickness="{Binding Path=StrokeThickness}"
StrokeDashArray="{Binding Path=StrokeDashArray}" Opacity="0.2">
<Polyline.BitmapEffect>
<BlurBitmapEffect Radius="2"/>
</Polyline.BitmapEffect>
</Polyline>
<Polyline Points="{Binding Path=Points}" x:Name="points"
Stroke="{Binding Path=Stroke}"
StrokeThickness="{Binding Path=StrokeThickness}"
StrokeDashArray="{Binding Path=StrokeDashArray}" />
</Canvas>
<DataTemplate.Triggers>…</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
<Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
<Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
<Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
<Setter Property="Border" Value="{StaticResource BorderDark}"/>
<Setter Property="MergeResources" Value="{StaticResource ResourcesDark}"/>
<Setter Property="GalleryTemplates" Value="{StaticResource GalleryDark}"/>
<Setter Property="MarkerTemplates" Value="{x:Static cfx:MarkerTemplates.Simple}"/>
</Style>
The GalleryTemplates property expects a ResourceDictionary where you supply styles for all our galleries, note the following key points
- If we do not find a template for a particular gallery we will use the template from the Simple style. This gives you a simple but not too basic style for most galleries, in this case we are only customizing bar and line
- Each style can provide defaults, for example the line will have a thickness of 3 and the markers will be size 10 if you do not modify the appropriate properties.
- Bars allow you to specify an alternate template for the first, middle and last stacks, this allows you to have a rounded top without having all intermediate segments rounded
- You can bind visibility of “effects” to a property called EffectsVisibility (shown here for the shadow of the line), this will be controlled by Chart.UseEffects
- You can also provide a ResourceDictionary that controls how the line markers look, we are using a built-in dictionary that generates simpler markers.
This is what our final style looks like

Chart FX for WPF includes the following built-in styles
- In our core ChartFX.WPF assembly we support Glass, Simple and Basic
- In the ChartFX.WPF.Motifs assembly we include Edge, Spotlight, Floating and Blinds
- In the ChartFX.WPF.Motifs.HandDrawn assembly we include HandDrawn
You can quickly switch styles in your app with a single line of code, if you add a reference to the extra 2 assemblies you will be able to browse through our styles in the ChartFX.WPF.Motifs namespace, remember that you are assigning a Style property so you have to then select the Style property (e.g. ChartFX.WPF.Motifs.Simple.Style)
We are considering adding Expression Dark to ChartFX.WPF.Motifs as well as other popular application styles, your feedback will let us know which styles we should focus on, but we wanted to show that is possible to completely control your charts appearance to make it integrated in your application.
JuanC
The following APIs were not harmed during the production of this post
Palette: Gives you control over all brushes and colors used in the chart.
Border: Allows you to change the chart border independently from the chart template.
GalleryTemplates and MarkerTemplates. Control how markers (bar, line, area, etc.) look
MergeResources: Additional resources such as scrollbar.
UseEffects: Hide shadows, reflections from the chart visuals.