Our Spakline integrated in a Grid

[Infragistics] Damyan Petev / Tuesday, February 21, 2012

With 11.2 we introduced the XamSparkline control, which is in essence a fully-functional chart but with the major addition of being extremely compact. This is so important as it is intended to fit inside a grid cell. While this control is still CTP in the current release, there’s nothing stopping you from experimenting and making use of its functionality right now. And just in case you missed – get to know this minimalistic control starting with the Introduction to the Infragistics Sparkline Control blog post by Atanas Dyulgerov. In it you can learn the basics of the control – while simple is yet another description you can give this XAML control, you will find it doesn’t really leave you wanting more – it is feature rich as well. The XamSparkline can display numeric and date entries in four different chart types, it can display a range bar which basically visualizes the area with acceptable or goal values. Then there’s also the array of highly customizable markers the Sparkline supports out of the box and a trend line with multiple calculation methods. And, yes, all that can fit in very limited space (e.g. inside a grid) and prove to have extremely high information per pixel ratio 

At this point, if you have been looking at our Silverlight Data Visualization Samples or the downloadable WPF version, you might be saying “Yes, I understand it’s meant to fit inside a grid and you keep saying that but I don’t see it anywhere!”. Not to worry – this is exactly what will be shown in this article.

Imagine a scenario where you have hierarchical data displayed effortlessly by a XamGrid, but consider this – what if your rows have 20 or more child entries and you need to find just some that have some sort of an issue? How would you get the required data fast, how can you analyse those entries fast? The natural answer for the latter is usually a visual representation - i.e a chart and in our case that would be a XamSparkline without a doubt. And since it is part of both Data Visualization products and because our XamGrid is now also cross-platform, this is done very easily and is also portable between the platforms. Here is the end result we are after:

Hierarchical xamGrid displaying child data using a xamSparkline with column display type and trendline.

As you can see in the child entries the values from the last two columns (the one that is a bit cut is the UnitsOnOrder, sorry about that) are presented by the chart as follows: 39, –23, 20. This makes spotting negative values very easy.

Setting up

First things first, taking into account this is a combination of Line of Business (LoB) and Data Visualization (DV) controls means you will need one of each – either a combination of NetAdvantage for WPF LoB and DV or NetAdvantage for Silverlight LoB plus DV, but then again trial packages will also do.

You will also need data. Following the scenario from above you would need hierarchical data of some kind. For simplicity's sake in my example I will use the DataUtil class that is available from our Help Topics in both Visual Basic and C#. Speaking of which you can as always find tons of useful information in the XamGrid Online Help for Silverlight or  WPF, even though it’s a shared XAML control, so those links are somewhat just to indulge your preferences.

Grab the preferred version of the DataUtil class and add it to your project – keep in mind the namespace when copying, which I’d suggest to change to your project’s namespace. When that is done link the namespace to your XAML page/window:

  1. xmlns:local="clr-namespace:SparklineInXamGrid"

In that case ‘SparklineInXamGrid’ is the namespace of my project. Then you can also add the Infragistics namespace:

  1. xmlns:ig="http://schemas.infragistics.com/xaml"

This namespace is the only needed for this case in Silverlight and WPF because both the XamSparkline and the XamGrid are shared XAML controls for both platforms. There are also references to a few assemblies required - InfragisticsSL4.v11.2.dll, InfragisticsSL4.Controls.Grids.XamGrid.v11.2.dll, InfragisticsSL4.Controls.Menus.XamMenu.v11.2.dll for Silverlight as thier naming suggests. The assemblies for WPF follow the same model - InfragisticsWPF4.v11.2.dll, InfragisticsWPF4.Controls.Grids.XamGrid.v11.2.dll, InfragisticsWPF4.Controls.Menu.XamMenu.v11.2.dll, with the addition of InfragisticsWPF4.DataManager.v11.2.dll.

At this point you have a project set up to start building, so begin by adding the DataUtil as a  resource in a scope you see fit:

  1. <local:DataUtil x:Key="data"/>

Now you can add the XamGrid control and bind it to the data’s hierarchical collection – the file provides a combination of Categories and Products we can use:

  1. <ig:XamGrid
  2.     ItemsSource="{Binding Source={StaticResource data},Path=CategoriesAndProducts}"
  3.     Margin="20"
  4.     Name="xamGrid"/>

The XamGrid will generate the columns based on the data and we can rely on that for this demo, as our goal is not fine-tuning the grid, for which you can again refer to the Help docs.

So far you should have a working application with hierarchical grid.

Adding the Sparkline

Again let’s go back to our scenario – you can now see in a relatively small scale ( the DataUtil is only a small data sample) how we can take advantage of compressed data. Say we want to manage easily the balance of products we have in stock and on order. That means a few values per category in our small scale example, but... imagine if you had 50 products in a category and you need to find those with low amounts in stock yet many on order so you can replenish their numbers in some way. This is where our Sparkline will come – to provide this crucial info for each category.

For that goal we can create an Unbound Column in our grid to hold the values to be displayed by XamSparkline controls. And to have those values we will set them using the converter we have to implement for the Unbound Column. So add a class to your project that would implement the IValueConverter Interface:

  1. namespace SparklineInXamGrid
  2. {
  3.     public class SourceConverter : IValueConverter
  4.     {
  5.  
  6.         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  7.         {
  8.             List<int> convertedValues = new List<int>();
  9.             foreach (Product prod in (value as Category).Products)
  10.             {
  11.                 convertedValues.Add(prod.UnitsInStock - prod.UnitsOnOrder);
  12.             }
  13.             return convertedValues;
  14.         }
  15.  
  16.         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  17.         {
  18.             throw new NotImplementedException();
  19.         }
  20.     }
  21. }

And add that as a resource to your XAML (now you see why we changed the namespace of the DataUtil):

  1. <local:SourceConverter x:Key="SourceConverter"></local:SourceConverter>

As you might have noticed already the value passed to the Convert method is used as an instance of the class Category, which is defined in our DataUtil class. And of course, the value this converter will receive would be from the context of the current row, which without a doubt would be the Category from the CategoryAndProducts collection. And better yet, it exposes a collection of products with their UnitsInStock and UnitsOnOrder properties we would use to calculate the balance and create a collection from – in this case a List, but a simple array of integers would do too. The returned values would become the ‘Value’ property of the Unbound Column. Now for the column itself:

  1. <ig:UnboundColumn Key="Balance"
  2.                   ValueConverter="{StaticResource SourceConverter}"
  3.                   IsSortable="False"
  4.                   IsSummable="False"/>

IsSortable and IsSummable are false by default as additional efforts on your side are required for those to work with Unbound Columns, so this above is just to remind and stress you might not need those in our case but you also don’t get them by default either. As you can see the Value converter is set for the whole column so we now have the values for each cell. What is left to do is define an Item template for the column that would consist of our XamSparkline and the finished code looks like so:

  1. <Grid x:Name="LayoutRoot" Background="White">
  2.     <ig:XamGrid ItemsSource="{Binding Source={StaticResource data},Path=CategoriesAndProducts}"
  3.                 Margin="20" Name="xamGrid">
  4.         <ig:XamGrid.Columns>
  5.             <ig:UnboundColumn Key="Balance" ValueConverter="{StaticResource SourceConverter}"
  6.                               IsSortable="False" IsSummable="False">
  7.                 <ig:UnboundColumn.ItemTemplate>
  8.                     <DataTemplate>
  9.                         <ig:XamSparkline ItemsSource="{Binding Value}"
  10.                                          ValueMemberPath=""
  11.                                          TrendLineType="LogarithmicFit"
  12.                                          TrendLineBrush="#FF14AAE2"
  13.                                          DisplayType="Column"
  14.                                          Width="200"                
  15.                                          Height="60"/>
  16.                     </DataTemplate>
  17.                 </ig:UnboundColumn.ItemTemplate>
  18.             </ig:UnboundColumn>
  19.         </ig:XamGrid.Columns>
  20.     </ig:XamGrid>
  21. </Grid>

The ItemSource of the control is bound to the Value property of the Unbound Column as explained above and since it’s a simple collection we don’t have a ValueMemberPath so we leave that one empty. The rest is up to you – we have columns with  a nice blue trend line. This is the template used in the screenshot from the start of the blog and here’s yet another one using the Line chart type along with a Normal range defined from –5 to 30 ( I made that up naturally) and some nice High and Low markers.

Using normal range is only useful if the data points don’t have huge variations as you are setting one range for all charts and on some due to their values it just might not be visible, so use with caution. Anyway, it does look nice (the green-ish area) and it can really help spot some odd fluctuations in your values:

Hierarchical xamGrid displaying child data using a xamSparkline with line display type, normal range and markers.

And the temple for that is:

  1. <ig:UnboundColumn.ItemTemplate>
  2.     <DataTemplate>
  3.         <ig:XamSparkline ItemsSource="{Binding Value}"
  4.                          ValueMemberPath=""
  5.                          DisplayType="Line"
  6.                          NormalRangeVisibility="Visible"
  7.                          NormalRangeFill="GreenYellow"
  8.                          NormalRangeMinimum="-5"
  9.                          NormalRangeMaximum="30"
  10.                          LowMarkerVisibility="Visible"
  11.                          HighMarkerVisibility="Visible"
  12.                          Width="200"                
  13.                          Height="60"/>
  14.     </DataTemplate>
  15. </ig:UnboundColumn.ItemTemplate>

Conclusion

The XamSparkline might be miniature but it’s built with fitting small areas in mind while still being very data-intensive. It makes a great combination with the XamGrid and since they are both shared across XAML product lines, the code for the latter can be easily moved back and forth. And such cooperation is surprisingly easy to get going – a single Unbound Column, a converter and an item template holding the Sparkline. And don’t be fooled by the few data points – this control is well capable of displaying a lot more in that same limited space:

XamSparkline displaying child data with 30 points using line display type, normal range and markers inside a hierarchical xamGrid cell.

And this is ‘just’ 30 data points and.. well, there’s clearly room for more

Yet again, check out the Silverlight Data Visualization Samples online or download the local WPF Samples.

As always you can download the demo project for this blog – this time containing both Silverlight and WPF projects. The solution has been cleaned, so make sure assembly references are all in check and build.