DataGrid customization with Elements 5: Sparklines, template selectors and more

Following on from earlier posts about our new DataGrid control in WPF Elements 5, today I’ll be demonstrating some deeper customization options by creating a financial data display demo. By making a Chart control with an embedded LineSeries and setting a couple of properties we can create a great looking Sparkline graph, which can then be used as a template for a DataGrid column consisting of those graphs. All of this is included in WPF Elements 5, and you can grab the 60 day fully featured trial here to get started. I’ll then look at creating a template selector to apply templates to cells depending on their data, and the demo will also use a bit of custom logic to highlight the largest and smallest values in the collections. The final result will end up like this:

To begin, declare a new DataGrid control in a XAML page and bind its ItemsSource property to a collection in a similar manner to Working with the Data Grid – Day 1. If we are to add charts to this DataGrid its model will need a property of a type that contains an ObservableCollection of DateTimeDouble objects, which the LineGraph will use to draw itself. Here’s an archive with example data structures illustrating the required behavior (which generate random points suitable for the purposes of this demo): DataModel.

Setting up the sparkline charts

Next, in the ResourceDictionary add the following DataTemplates containing the formatted charts. The Chart control in WPF Elements 5 has heaps of customization options, and with a few simple tweaks the LineSeries can display a great looking Sparkline chart. Here’s one possible look for a Sparkline template:

<DataTemplate x:Key="BidChartCell">
  <ms:Chart LegendPosition="None" TitleTemplate="{x:Null}" Padding="3">
    <ms:LineSeries ItemsSource="{Binding BidTrend.Data1}" AlwaysShowYAxisZero="False" YAxisDataBuffer="1000" />
    <ms:Chart.XAxis >
      <ms:ChartAxis Visibility="Collapsed" />
    </ms:Chart.XAxis>
    <ms:Chart.YAxis>
      <ms:ChartAxis Visibility="Collapsed" />
    </ms:Chart.YAxis>
  </ms:Chart>
</DataTemplate>

The chart declared in that DataTemplate is going to look rather unnatural in any place larger than a DataGrid cell, so let’s apply it to a column in our DataGrid by setting its DisplayTemplate property:

<ms:DataGrid ItemsSource="{Binding Data}" AllowEditing="False">
  <ms:DataGrid.Columns>
    <ms:DataGridColumn PropertyName="BidTrend"
                       DisplayTemplate="{StaticResource BidChartCell}"
                       Header="Bid Trend"/>
  </ms:DataGrid.Columns>
</ms:DataGrid>

Pretty easy! If you were to increase the rows in the model you’d notice the performance is speedy even with dozens of charts on screen, and stays that way during resizing, dynamic data updating and similar tasks.

Showing additional data with template selectors

Now how about formatting the Change columns to show an image based on the data in each cell? One solution would be to create a custom class that derives from DataTemplateSelector and overrides SelectTemplate(). Here’s a snippet of the implementation with logic that returns a template based on whether the cell’s Double is positive or negative:

public class ChangeDataTemplateSelector : DataTemplateSelector
{
  public override DataTemplate SelectTemplate(object item, DependencyObject container)
  {
    FrameworkElement element = container as FrameworkElement;
 
    if (element != null && item != null)
    {
      Entry entryItem = item as Entry;
      if (ChangeType == CellChangeType.Bid)
      {
        if (entryItem.BidChange < 0)
        {
          return NegativeChangeTemplate;
        }
        else if (entryItem.BidChange > 0)
        {
          return PositiveChangeTemplate;
        }
      }
      else
      {
        if (entryItem.AskChange < 0)
        {
          return NegativeChangeTemplate;
        }
        else if (entryItem.AskChange > 0)
        {
          return PositiveChangeTemplate;
        }
      }
    }
    return NoChangeTemplate;
  }
 
  public DataTemplate PositiveChangeTemplate { get; set; }
}

The full code with the other two properties and the enum is contained in the archive at the bottom of this post. Back in the XAML, add the DataTemplates that are to be applied to the cell to the ResourceDictionary (here’s one of four required):

<DataTemplate x:Key="PositiveBidChangeTemplate">
  <Grid HorizontalAlignment="Center" x:Name="PositiveBidCell">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="35" />
    <ColumnDefinition Width="20" />
    </Grid.ColumnDefinitions>
    <TextBlock Text="{Binding BidChange}" HorizontalAlignment="Right"
               VerticalAlignment="Center" Margin="0,0,6,0" />
    <Image Source="../Images/up.png" Width="16" Height="16" Grid.Column="1" />
  </Grid>
</DataTemplate>

We can now declare an instance of our DataTemplateSelector and set its properties to our DataTemplates. The Bid selector will look like this:

<local:ChangeDataTemplateSelector x:Key="BidChangeSelector"
                                  PositiveChangeTemplate="{StaticResource PositiveBidChangeTemplate}"
                                  NegativeChangeTemplate="{StaticResource NegativeBidChangeTemplate}"
                                  ChangeType="Bid"
                                  NoChangeTemplate="{StaticResource NoChangeBidTemplate}" />

Now that has been set up, it’s a simple matter of setting the DisplayTemplateSelector property on the appropriate DataGridColumn that you wish to apply the templates to. We may as well make the column’s title look a bit nicer at the same time.

<ms:DataGridColumn PropertyName="BidChange" Header="Bid Change"
                   DisplayTemplateSelector="{StaticResource BidChangeSelector}" />

That will get the Change and Trend columns looking like the screenshot at the top of this post. In a future post I’ll show how to extend the model to record the highest and lowest data, and use XAML triggers to format cells based upon that information. In the meantime, check out the archive below for the full code from this post.

DataGrid with sparklines and template selectors

And don’t forget to download the 60-day trial of WPF Elements and try out your own designs!

Tagged as WPF Elements

Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top