Skip to main content

Styling Charts with the Silverlight Toolkit

Important Note:

This article refers to a previous version of Silverlight.  The information presented here is not accurate for Silverlight 4, and will not produce the same results.

Author: Pete Brown, Lead Architect, Applied Information Sciences, Inc. , MVP Client Application Dev (Silverlight / WPF)

Expression Newsletter, subscribe now to get yours.

Summary

In this article, Pete Brown covers various ways to alter the look and feel for the chart control included in the Silverlight Toolkit. While focusing primarily on the Pie Chart, the techniques are transferable to the other types of charts in the toolkit. This article is recommended for designers who are comfortable working with XAML or developers who are comfortable working with Expression Blend.

Introduction

The Silverlight Toolkit is a set of controls and styles from Microsoft, made available outside the normal Silverlight development cycle. Full sourced code, tests and XAML is available on CodePlex.

While the toolkit includes tons of great controls, one of the most anticipated in the business application development community is the native Silverlight charting. Vector-based presentation technologies like Silverlight and WPF naturally lend themselves to the easy creation of charting. However, building a robust charting control is a non-trivial task. Luckily, the Silverlight Toolkit team has already done all the heavy lifting for you.

[Note: This article was written using the December 9 release of the Toolkit. ]

The charting component includes horizontal and vertical bar charts, bubble charts, pie charts, line charts and scatter charts. Each of those types allows for rich styling capabilities including all the visuals and animation for the elements.

Getting Started with a Simple Pie Chart

Let’s create a simple pie chart. Create a Silverlight project as you normally would, and add a reference to the Silverlight Toolkit Charting DLL and the main controls DLL. The location for the two will depend upon where you installed the toolkit binaries.

Next you’ll want to either drag a chart control into your markup (or on to your Blend design surface) or manually create the xmlns. As I am very particular about naming for my namespaces, I prefer to type it in manually using Visual Studio’s XAML editor:

xmlns : charting ="clr-namespace:Microsoft.Windows.Controls.DataVisualization.Charting;
assembly=Microsoft.Windows.Controls.DataVisualization"

xmlns : datavis ="clr-namespace:Microsoft.Windows.Controls.DataVisualization;
assembly=Microsoft.Windows.Controls.DataVisualization"

xmlns : controls ="clr-namespace:Microsoft.Windows.Controls;
assembly=Microsoft.Windows.Controls"

xmlns : sys ="clr-namespace:System;assembly=mscorlib"

This tells Silverlight from where to pull the controls we prefix with listed xmlns. The first we’ll use for the chart. The “datavis” one we’ll use for styling, the “controls” and “sys” will be used to allow us to mock up data directly in XAML. In a regular application with bound data, you typically will not require the “controls” and “sys” namespace declarations.

While we’re here, let’s continue in the XAML editor for the moment, so we can better understand the structure of the control.

Chart Structure

The Chart control itself doesn’t really define much about the chart other than the regions within which the various parts would be displayed. It doesn’t, for example, control whether it is a pie chart or a bar chart. Reasonable people could assume we’d have something like either of these:

        < charting : PieChart />
        < charting : Chart Type ="Pie" />

But what we do have is even more flexible, allowing for the addition of new chart types without altering existing enumerations or flooding the namespace with lots of XyzChart controls. The type of the chart is defined by the type of Series you add to the chart. The currently supported series include:

  • BarSeries
  • BubbleSeries
  • ColumnSeries
  • LineSeries
  • PieSeries
  • ScatterSeries

Each of those corresponds to what we would think of as the type of the chart. For example, here’s the markup for a simple Pie Chart with hard-coded data (note that the data has only a single dimension – no real label – and is not bound using any of the nifty binding expressions):

< charting : Chart x : Name ="ExampleChart">
    < charting : PieSeries >
        < charting : PieSeries.ItemsSource >
           <controls:ObjectCollection>
               <sys:Double>1</sys:Double>
               <sys:Double>2.3</sys:Double>
               <sys:Double>3.5</sys:Double>
               <sys:Double>5</sys:Double>
            </controls:ObjectCollection>
        </ charting : PieSeries.ItemsSource >
    </ charting : PieSeries >
</ charting : Chart >

While the XAML method of setting the ItemsSource works well for prototyping, If you prefer to set the data in code, you can do so like this:

< charting : Chart x : Name ="ExampleChart">
    < charting : PieSeries />
</ charting : Chart >
void Page_Loaded(object sender, RoutedEventArgs e)
{
    SetChartData();
}

private void SetChartData()
{
    List<double> data = new List<double>() { 1, 2.3, 3.5, 5 };

    ((PieSeries)ExampleChart.Series[0]).ItemsSource = data;   
}

Either way, the end result is a chart which looks like this:

Not bad at all for a few lines of markup! The default visuals for the chart include a gradient background for the chart and the legend, a border around the whole chart, and a Style Palette with muted colors and radial gradients for highlights.

The Style Palette

One of the easiest ways to customize the look of your chart is to alter the Style Palette. The Style Palette provides a set of styles that the series will use when rendering its individual data points. In the case of the pie chart, a data point is a slice of the pie. On a bar chart, the data point would be a bar.

If you want a simple monochrome chart, you can provide a single style, like this:

< charting : Chart x : Name ="ExampleChart">
    < charting : PieSeries >
   
         <!-- Styles for the pie slices -->
        < charting : PieSeries.StylePalette >
            < datavis : StylePalette >
                < Style TargetType ="charting:PieDataPoint">
                    < Setter Property ="Background"
                           Value="Black">
                   </Setter>
               </Style>
           </datavis:StylePalette>
        </charting:PieSeries.StylePalette>
        <!-- End Styles -->

        <charting:PieSeries.ItemsSource>
            <controls:ObjectCollection>
               <sys:Double>1</sys:Double>
               <sys:Double>2.3</sys:Double>
               <sys:Double>3.5</sys:Double>
               <sys:Double>5</sys:Double>
            </ controls : ObjectCollection >
        </ charting : PieSeries.ItemsSource >
    </ charting : PieSeries >
</ charting : Chart >

Since we’ve provided a style palette, the chart will constrain itself to using only the styles included within. The chart will round-robin through the provided styles, using them for your datapoints in natural order. In this case, we provided only a single style, so the result looks like this:

(Note that I cropped off the black border to keep the image smaller in this article. We’ll deal with actually removing it when we style the whole control later.)

As you would expect, providing two styles will allow the chart to alternate between them:

...
< charting : PieSeries.StylePalette >
    < datavis : StylePalette >
        < Style TargetType ="charting:PieDataPoint">
            < Setter Property ="Background"
                   Value="Black">
           </Setter>
        </Style>
        <StyleTargetType="charting:PieDataPoint">
           <Setter Property="Background"
                   Value="DarkGray">
           </Setter>
        </Style>
   </datavis:StylePalette>
</charting:PieSeries.StylePalette>
...

The style can alter properties other than just the background. You can, for example, change the BorderBrush. Some settings such as the border thickness may produce artifacts in the rendering, at least for the pie chart, so I would avoid those, or at least keep an eye out when you play with them. They do work better in charts that do not share borders, such as a bar or column chart.

You can include as many styles as you want. If you include fewer styles than data points, you’ll get some repetition. If you include more, the extras simply won’t be used.

If you want to reuse the styles across multiple types of charts, have the target type be Control rather than a specific type of data point. This will make it easier to reuse, but you’ll need to be careful if you use control templates as we do later in this article.

Providing a custom style palette is one of the easiest ways to customize the look of your chart. Next we’ll crack open the rest of the chart and see what it’s made of.

Dissecting the Chart Template

The chart has four primary areas and four related styles:

PropertyStyle Target Type
ChartAreaStyleGrid
LegendStyleLegend (a control similar to an ItemsControl with a Title)
PlotAreaStyleGrid
TitleStyleTitle (a ContentControl)


The areas can be seen in the example chart below. I added a 5px margin around the PlotArea so the ChartArea would stand out. On a pie chart, they otherwise occupy the same space, with the PlotArea being in front. On charts with more axes (such as a LineSeries or ScatterSeries), the PlotArea is the area inside the axes and the axes and labels are in the ChartArea, outside the PlotArea.

The part of the template that controls the overall arrangement of the chart elements looks like this (comments added for clarity):

< ControlTemplate TargetType ="charting:Chart">
    < Border Background ="{ TemplateBinding Background }"
           BorderThickness="{TemplateBinding BorderThickness}"
            Padding="10">
        <Grid>
           <Grid.RowDefinitions>
               <RowDefinition Height="Auto" />
               <RowDefinition Height="*" />
           </Grid.RowDefinitions>
           
           <!-- Title -->
           <datavis:TitleStyle="{TemplateBinding TitleStyle}"
                           Content="{TemplateBinding Title}" />
           
           
           <Grid Margin="0,15,0,15"
                 Grid.Row="1">
               <Grid.ColumnDefinitions>
                   <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
               </Grid.ColumnDefinitions>
               
               <!-- Legend -->
               <datavis:Legendx:Name="Legend"
                               Style="{TemplateBinding LegendStyle}"
                                Grid.Column="1"
                               Title="{TemplateBinding LegendTitle}"
                               BorderBrush="{x:Null}"
                               Background="{x:Null}" />
               
               <!-- Chart Area -->
               <Grid x:Name="ChartArea"
                     Style="{TemplateBinding ChartAreaStyle}">
                   
                   <!-- Plot Area -->
                   <Grid x:Name="PlotArea"
                         Style="{TemplateBinding PlotAreaStyle}"
                         Background="{x:Null}">
                       <Grid x:Name="GridLinesContainer" />
                       <Grid x:Name="SeriesContainer" />
                       <Border BorderBrush="{x:Null}"
                               BorderThickness="1" />
                   </Grid>
                   
               </Grid>
               
           </Grid>
        </Grid>
   </Border>
</ControlTemplate>

Given the layout there, you may move the pieces around just about any way you like. One of the great things about Silverlight (and WPF) is that you don’t have to rely on a third-party to provide you with a chart that has properties like LegendPosition (with values Top, Left, Bottom, Right), the control author simply needs to make sure the legend is positioned via elements in the template (a simple Grid column in this case). As a designer, you have complete control over its placement and style.

Chart Template in Blend

With that in mind, let’s go crack the style open in Blend. Select the Chart (not the PieSeries) for the pie chart, and edit the template. We’ll create a new style and keep it in our Page.xaml for this example.

The resulting template is pretty easy to understand, and corresponds to the annotated picture and XAML above.

Remember that black border around the chart? The source for that is the outermost Border element. As you would expect, the color is bound to the BorderBrush for the control, so you can either edit the border directly, or set the BorderBrush for the control. Setting the brush on the control is less intrusive, removing the border completely makes more sense if you don’t need it for anything else.

I’m going to do the simple thing here and simply set the border to a transparent BorderBrush directly. Since the border brush for the border is template-bound to the chart control, you’ll need to reset it or convert to a local value if you want to edit it directly.

Once you have finished styling the outermost chart, you have a couple choices. You can either style the inner parts (ChartArea, PlotArea) directly, or you can create separate styles for them. Since I have the control template open in front of me, I’m going to edit them directly. You would want to create discrete styles if you only needed to style a small portion of the chart and/or you wanted to reuse that discrete style in other chart styles in the application.

Another reason to edit the discrete styles would be if you are sharing this with other members of a design team. The other members would rightly expect the style information to be contained in the XyzStyle properties rather than hardcoded directly in the template.

To edit the existing styles, and avoid duplicating them with new styles, select the object you want (the Title, for example) and select Object->Edit Style->Edit Style:

Once I cleared out the various border and background brushes, the chart ended up like this:

In many cases, a minimalist chart will fit in better stylistically with your own application. You can provide the chrome outside of the chart itself and you can, of course, provide a nicer set of styles for the data points.

Legend Style

The legend is the only complex element style in the chart control itself. Let’s dig into that just a bit. Before we do, though, we really need to give ourselves a bit more data to work with. So far, our datapoints and the legends that come from them aren’t really representative of what we’d see in a real application.

We’ll keep the rest of the style simple and start with a clean chart implementation – no re-templating.

< charting : Chart x : Name ="ExampleChart"
               Title="Hello World" >
   <charting:PieSeries>
   </charting:PieSeries>
   
</charting:Chart>

Create the ChartPointData Class

Since Silverlight XAML can’t use generics directly, we can’t simply use something like KeyValuePair<TKey, TValue>. Instead, we’ll need to create a purpose-built class that contains the label and the value. Pretty simple, really:

namespace PeteBrown.ExpressionNewsletterCharts
{
    public classChartPointData
    {
        public double Value { get; set; }
        public string Label { get; set; }
    }
}

We can now use instances of this class rather than sys:Double. First, we’ll need to create the xmlns entry for the local namespace:

xmlns : local ="clr-namespace:PeteBrown.ExpressionNewsletterCharts"

Then we can add our chart data:

< charting : PieSeries.ItemsSource >
    < controls : ObjectCollection >
        < local : ChartPointData Value ="1"
                             Label="Pete" />
        <local:ChartPointData Value="3"
                             Label="David" />
        <local:ChartPointData Value="9"
                             Label="Justin" />
        <local:ChartPointData Value="5"
                             Label="Shawn" />
        <local:ChartPointData Value="5"
                             Label="John" />
   </controls:ObjectCollection>
</charting:PieSeries.ItemsSource>

Bind the Points

Finally, we’ll need to set up some binding. Change the PieSeries declaration to read like this:

< charting : PieSeries DependentValueBinding ="{ Binding Value }"
                   IndependentValueBinding ="{Binding Label}">

The dependent value is the value displayed on the chart. The independent value is the label shown in the legend. That description is sufficient for our Pie Chart, but is far from complete. For a more detailed description of Dependent and Independent variables, see this Wikipedia Entry.

Of course, you don’t need to add the data in XAML, you can do it in the code behind the XAML. However, I find that a designer will have better luck if they can directly manipulate the data in the XAML to try out different combinations and to debug/test their style work. You’ll of course replace this with a DataContext set statement once you move forward.

Run it and you’ll get this:

As a designer, you now have some reasonable data to work with. Nothing is worse than creating a design to some dummy data only to find out the real data is shaped quite differently.

Legend

Recall that the legend is the area on the right of the chart shows our pie slice colors and the independent values. Let’s crack open the legend now. The full template looks like this:

And in XAML:

< Style x : Key ="LegendStyle1"
       TargetType="datavis:Legend">
   <Setter Property="BorderBrush"
            Value="Black" />
   <Setter Property="BorderThickness"
            Value="1" />
   <Setter Property="IsTabStop"
            Value="False" />
   <Setter Property="TitleStyle">
        <Setter.Value>
           <Style TargetType="datavis:Title">
               <Setter Property="Margin"
                       Value="0,5,0,10" />
               <Setter Property="FontWeight"
                        Value="Bold" />
               <Setter Property="HorizontalAlignment"
                       Value="Center" />
           </Style>
        </Setter.Value>
   </Setter>
   <Setter Property="Template">
        <Setter.Value>
           <ControlTemplate TargetType="datavis:Legend">
               <Border Background="{TemplateBinding Background}"
                       BorderBrush="{TemplateBinding BorderBrush}"
                       BorderThickness="{TemplateBinding BorderThickness}"
                       Padding="2">
                   <Grid>
                       <Grid.RowDefinitions>
                           <RowDefinition Height="Auto" />
                           <RowDefinition />
                       </Grid.RowDefinitions>
                       
                       <!-- Title -->
                       <datavis:TitleStyle="{TemplateBinding TitleStyle}"
                                      Grid.Row="0"
                                      Content="{TemplateBinding Title}" />
                       
                       <!-- ScrollViewer for Items -->
                       <ScrollViewer BorderThickness="0"
                                     IsTabStop="False"
                                     Padding="0"
                                     Grid.Row="1"
                                     VerticalScrollBarVisibility ="Auto">
                           
                           <!-- StackPanel containing all legend items -->
                             <StackPanelMargin="10,0,10,10"
                                       x:Name="LegendItemsArea"
                                       Grid.Column="1" />
                       </ScrollViewer>
                   </Grid>
               </Border>
           </ControlTemplate>
        </Setter.Value>
   </Setter>
</Style>

From this, you can see that you can change the layout of the legend, change the panel type (for example, use a WrapPanel instead of a StackPanel), and allow or eliminate scrolling.

Legend Item Style

If you want to modify the look of the legend items themselves, you’ll use the LegendItemStyle, which is a member of the Series, not of the Legend. The default template looks like this (key added by me):

< Style x : Key ="LegendItemStyle" TargetType ="charting:LegendItem">
    < Setter Property ="IsTabStop"
           Value="False" />
   <Setter Property="Template">
        <Setter.Value>
           <ControlTemplate TargetType="charting:LegendItem">
               <StackPanel Orientation="Horizontal">
                   <Rectangle Width="8"
                              Height="8"
                              Fill="{BindingBackground}"
                              Stroke="{BindingBorderBrush}"
                              StrokeThickness="1"
                              Margin="0,0,3,0" />
                   <datavis:TitleContent="{TemplateBinding Content}" />
               </StackPanel>
           </ControlTemplate>
        </Setter.Value>
   </Setter>
</Style>

To change that, simply add the style to your resources, and reference it either directly from the series style using a setter, or via the chart markup like this:

< charting : PieSeries DependentValueBinding ="{ Binding Path =Value}"
                   IndependentValueBinding ="{Binding Path=Label}"
                   LegendItemStyle="{StaticResource LegendItemStyle}">

For example, this control template for the legend replaces the stackpanel with a grid, sets some margins, changes the font color, and eliminates the 8px sizing of the rectangle.

< ControlTemplate TargetType ="charting:LegendItem">
    < Grid >
        < Rectangle Fill ="{ Binding Background }"
                  Stroke="{BindingBorderBrush}"
                  StrokeThickness="1"
                  Margin="1" />
        <datavis:TitleContent="{TemplateBinding Content}"
                      Margin="4"
                      Foreground="White"/>
   </Grid>
   
</ControlTemplate>

The resulting legend looks like this:


Using the Tooltip Instead of a Legend

What if you don’t want to use the legend at all? In that case, you can modify the tooltip to display the legend information. The way you do this is not immediately intuitive: you need to re-template the PieDataPoint, but you need to add a dummy PieDataPoint in order to do that. That’s easy to do, as the PieDataPoint is a control like any other.

Inside the page, but outside of the chart, add the following:

< charting : PieDataPoint x : Name ="DummyPointForStyling" />

Now you can modify the style, including the tooltip. The full style looks like this:

<Style x:Key="PieDataPointStyle1"
  TargetType="charting:PieDataPoint">
 <Setter Property="Background" Value="Orange" />
 <Setter Property="BorderBrush" Value="White" />
 <Setter Property="BorderThickness" Value="1" />
 <Setter Property="IsTabStop" Value="False" />
 <Setter Property="RatioStringFormat" Value="{}{0:p2}" />
 <Setter Property="Template">
   <Setter.Value>
     <ControlTemplate TargetType="charting:PieDataPoint">
       <Grid x:Name="Root" Opacity="0">
         <vsm:VisualStateManager.VisualStateGroups >
           <vsm:VisualStateGroup x:Name="CommonStates">
             <vsm:VisualStateGroup.Transitions>
               <vsm:VisualTransition GeneratedDuration="0:0:0.1" />
             </vsm:VisualStateGroup.Transitions>
             <vsm:VisualState x:Name="Normal" />
             <vsm:VisualState x:Name="MouseOver">
               <Storyboard>
                 <DoubleAnimation Duration="0"
                   Storyboard.TargetName ="MouseOverHighlight"
                   Storyboard.TargetProperty ="Opacity"
                   To="0.6" />
               </Storyboard>
             </vsm:VisualState>
           </vsm:VisualStateGroup>

           <vsm:VisualStateGroup x:Name="SelectionStates">
             <vsm:VisualStateGroup.Transitions>
               <vsm:VisualTransition GeneratedDuration="0:0:0.1" />
             </vsm:VisualStateGroup.Transitions>
             <vsm:VisualState x:Name="Unselected" />
             <vsm:VisualState x:Name="Selected">
               <Storyboard>
                 <DoubleAnimation Duration="0"
                   Storyboard.TargetName ="SelectionHighlight"
                   Storyboard.TargetProperty ="Opacity"
                   To="0.6" />
               </Storyboard>
             </vsm:VisualState>
           </vsm:VisualStateGroup>
                     
           <vsm:VisualStateGroup x:Name="RevealStates">
             <vsm:VisualStateGroup.Transitions>
               <vsm:VisualTransition GeneratedDuration="0:0:0.5" />
             </vsm:VisualStateGroup.Transitions>
             <vsm:VisualState x:Name="Shown">
               <Storyboard>
                 <DoubleAnimation Duration="0"
                   Storyboard.TargetName ="Root"
                   Storyboard.TargetProperty ="Opacity"
                   To="1" />
               </Storyboard>
             </vsm:VisualState>
             <vsm:VisualState x:Name="Hidden">
               <Storyboard>
                 <DoubleAnimation Duration="0"
                   Storyboard.TargetName ="Root"
                   Storyboard.TargetProperty ="Opacity"
                   To="0" />
               </Storyboard>
             </vsm:VisualState>
           </vsm:VisualStateGroup>
         </vsm:VisualStateManager.VisualStateGroups >

         <!-- This is the geometry for the slice -->
         <Pathx:Name="Slice"
           Fill="{TemplateBinding Background}"
           Stroke="{TemplateBinding BorderBrush}"
           Data="{TemplateBinding Geometry}">
           <ToolTipService.ToolTip>
             <StackPanel>
               <ContentControl Content=                  "{TemplateBindingFormattedDependentValue}" />
               <ContentControl Content=
                 "{TemplateBindingFormattedRatio}" />
             </StackPanel>
           </ToolTipService.ToolTip>
         </Path>
                  
         <!-- These are used by VSM for state visualization -->
         <Path x:Name="SelectionHighlight"
           IsHitTestVisible="False"
           Opacity="0"
           Fill="Red"
           Data="{TemplateBinding GeometrySelection}" />
                   
         <Path x:Name="MouseOverHighlight"
           IsHitTestVisible="False"
           Opacity="0"
           Fill="White"
           Data="{TemplateBinding GeometryHighlight}" />
       </Grid>
     </ControlTemplate>
   </Setter.Value>
 </Setter>
</Style>

The tooltip is included in the path for the pie slice. By default, it shows the number and the ratio. There are a few other properties you can bind to, though, to provide additional information:

PropertyDescription
DependentValueThe value that the pie slice represents
FormattedDependentValueDependentValue formatted using the format string in DependentValueStringFormat
IndependentValueThe label for the pie slice
RatioRatio of this slice to the whole pie
FormattedRatioRatio formatted using the format string in RatioStringFormat


To see a few of them in action, you can change the tooltip like this:

< ToolTipService.ToolTip >
    < StackPanel >
        < ContentControl Content ="{ TemplateBinding IndependentValue }" />
        < ContentControl Content ="{ TemplateBinding FormattedDependentValue }" />
        < ContentControl Content ="{ TemplateBinding FormattedRatio }" />
    </ StackPanel >
</ ToolTipService.ToolTip >

Then make sure this template is used for each pie slice by modifying the style palette. You’ll need to turn the style into a ControlTemplate in order to do this. We could keep it a style, but then we’d need one complete copy for each StylePalette entry. By extracting the template, we can add unique style information over it, while avoiding the duplication of the ControlTemplate. The easiest way to do that is to just extract the ControlTemplate from the style and provide it with a key like ”PieDataPointTemplate”. Then, in each of the styles in the StylePalette, add:

< Setter Property ="Template" Value="{StaticResource PieDataPointTemplate}" />

Move the new ControlTemplate in the XAML above the chart style (or else you’ll get an error that the resource is not found). Finally, make sure you comment out the dummy PieDataPoint.

The resulting tooltip looks like this. Since the data is now in the chart itself, we can eliminate the legend without losing any information.

More DataPoint Styling

You’ll notice that the PieDataPoint is the first control we’ve seen so far which includes visual states. There’s quite a bit you can do with Visual State Manager, so if you haven’t used it yet, I recommend playing with one of the straight-forward yet complete examples such as the Button.

We’re going to modify the PieDataPoint to include some animation on show. You can take this example and expand it to handle other states.

Uncomment the dummy PieDataPoint we created for styling, and change it from having a Style to using the Template we created.

< charting : PieDataPoint x : Name ="DummyPointForStyling"
   Template ="{ StaticResource PieDataPointTemplate }" />

In Blend, using the Breadcrumb Bar, edit the current template for the PieDataPoint. That will edit the template that is shared by all of the styles in our StylePalette.

The first thing we’re going to do is give each slice a little “bounce” when it appears.

Select the “Shown” state from the RevealStates group in the States pane. Ensure the Shown state is currently in record mode, and then expand its timeline.

Create a keyframe at zero and set the RenderTransform Scale X and Scale Y of the slice both to zero. This is our starting point.

Next, at 0.5 seconds, record a keyframe and set the Scale X and Scale Y both to 1.2. This is the second keyframe.

Finally, at 0.7 seconds, record a keyframe and set the Scale X and Scale Y both to 1.0. This is the third and final keyframe.

The bounce is pretty linear at this point, so we’ll want to adjust the easing curve to control the values in a non-linear way. Click on the keyframe marker for the second keyframe and adjust the KeySpline so the transform starts off slowly and then accelerates towards the keyframe value. Something like this will work:

 

You can adjust the curve for more dramatic effects if you desire. Adjust the final keyframe to bounce in a little.

Finally, we want to remove the DoubleAnimation that is controlling opacity on show. You can either manually zap that from the Xaml, or use Blend to remove it. I find editing the Xaml to be easier in this case. Remove this storyboard from the “Shown” visual state.

< DoubleAnimation Duration ="0"
      Storyboard.TargetName ="Root"
      Storyboard.TargetProperty ="Opacity"
      To ="1" />

Next select “Root” and change its Opacity to 100%. It is currently set to zero because the default Show animation changes the opacity from 0 to 1 over time.

Finally, change the transition time on “RevealStates” to 0.7 to correspond with our new timelines.

If you run it at this point, you’ll notice that the pie starts off full size, shrinks, and then expands again. To fix this, we need to change the starting values for the ScaleTransform to be zero. This is the last thing we do because it makes it pretty hard to style the slice when it is sized at 0%.

The final XAML for the Shown visual state looks like this:

<vsm:VisualState x:Name="Shown">
  <Storyboard>
     <DoubleAnimationUsingKeyFrames BeginTime ="00:00:00"
        Storyboard.TargetName ="Slice"
        Storyboard.TargetProperty ="(UIElement.RenderTransform).
           (TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
        <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1.2"
            KeySpline="0.964999973773956,0.188999995589256,
                       0.889999985694885,0.449000000953674" />
         <SplineDoubleKeyFrame KeyTime="00:00:00.7000000" Value="1"
            KeySpline ="0.280000001192093,0.768999993801117,
                        0.307000011205673,0.833999991416931" />
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
         Storyboard.TargetName ="Slice"
         Storyboard.TargetProperty ="(UIElement.RenderTransform).
            (TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
         <SplineDoubleKeyFrame KeyTime="00:00:00 Value="0" />
         <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1.2"
            KeySpline="0.964999973773956,0.188999995589256,
                       0.889999985694885,0.449000000953674" />
         <SplineDoubleKeyFrameKeyTime="00:00:00.7000000" Value="1"
            KeySpline="0.280000001192093,0.768999993801117,
                       0.307000011205673,0.833999991416931" />
      </DoubleAnimationUsingKeyFrames>
   </Storyboard>
</vsm:VisualState>

The pie slices all pop in simultaneously in this case. If you want to make it a little more interesting, you can change the AnimationSequence on the PieSeries to something other than Simultaneous:

< charting : PieSeries DependentValueBinding ="{ Binding Path =Value}"
                   IndependentValueBinding ="{Binding Path=Label}"
                   AnimationSequence="FirstToLast">

The resulting animation will pop the pieces in one after another with a slight delay between the start of each. Here’s a screenshot of the animation in progress:

If you take this approach, I recommend tightening the animation so it is no longer than 1/3 second or so.

Expanded Techniques

The Chart controls are open and flexible enough to support methods of styling not originally envisioned by the team when they created the control. Two examples of this include absolutely positioned gradient and overlays, both of which will be covered outside of this article.

Absolutely Mapped Gradient

This technique is useful when you want to maintain the separation between the different pie slices, but have a uniform look to the gradient. In this case, I wanted to have a darker border all around the pie, giving a pseudo raised look to all of the slices. You can also use this to have a single gradient cover all slices, with a single highlight spot at the upper left (a radial gradient works well for this).

While you can implement this technique without any code, you quickly run into scaling issues. Fortunately, David Anson on the Silverlight Toolkit team has put together a great blog post with the code you’d need to implement this in your own application. For more information on this technique, please see Yummier pies! – Delay’s Blog

Overlays

Overlays include special glass effects and other techniques which may require more than a simple gradient, or multiple gradients. Typically this is used in concert with the absolutely mapped gradient technique. Overlays will be covered in my blog in an upcoming post.

Conclusion

The chart control included with the Silverlight toolkit has some great default visuals, but also provides you with the ability to customize those as you would any other Silverlight controls. We’ve only covered a small portion of what you can do here, but the techniques shown can be easily applied to the other series types as well as expanded upon to create totally different effects.


Pete Brown is a Microsoft MVP for Client Application Development (Silverlight and WPF), an INETA Speakers Bureau Speaker, and an Architect/Project Manager for Applied Information Sciences in the Washington, DC area. From his first sprite graphics and custom character sets on the Commodore 64 to 3d modeling and design through to Silverlight, Surface, Xna, and WPF, Pete has always had a deep interest in programming, design, and user experience. Pete’s involvement in Silverlight goes back to the Silverlight 1.1 alpha application that he co-wrote and put into production in July 2007. In his spare time, Pete enjoys programming, blogging, designing and building his own woodworking projects and raising his two children with his wife in the suburbs of Maryland.