Visiblox for Windows Phone 7 Beta was released a few days ago (
see the announcement post here). This posts shows how to get
started with it and create line, bar and pie series, enable
selection and add zooming and panning behaviours to them.
The structure of the article is as follows:
Line Series
Before getting started you need to install the Silverlight Toolkit for
Windows Phone and then download the component dll from the download page. After
having done so, unpack the zip and reference
Visiblox.Charts/Visiblox.Charts.WP7/Visiblox.Charts.dll.
Creating a Chart
To get started with charting you first need to create a Chart
object. As with most things in Silveright, this can be done both in
XAML and in code-behind: in this post we'll be doing most of what's
possible in XAML. Creating an empty chart can be done by declaring
a Chart element in XAML (optionally setting its Width and
Height):
<phone:PhoneApplicationPage
(...)
xmlns:charts="clr-namespace:Visiblox.Charts;assembly=Visiblox.Charts">
(...)
<charts:Chart Width="700" Height="400">
</charts:Chart/>
</phone:PhoneApplicationPage >
Adding the Series to the
Chart
Once we have the Chart object, we need to add series to it.
Adding a series consists of two steps: adding series (of type
IChartSeries) and setting the data of this series.
The series can be a
LineSeries,
BarSeries,
ColumnSeries,
BandSeries or
StaircaseSeries in the beta WP7 component. The data can be set
either by manually creating a DataSeries or by binding to a list of
model items by using BindableDataSeries.
Creating a LineSeries with Manually Created Data
The code for creating a LineSeries with manually created data is
the following. First, let's add a LineSeries to the Chart in
XAML:
<charts:Chart x:Name="MyChart" Width="700" Height="400">
<charts:Chart.Series>
<charts:LineSeries/>
</charts:Chart.Series>
</charts:Chart>
Now we need to manually create the data for the series and
assign this data to it. Let's do this in the code behind:
// Create a DataSeries<DateTime, double> and assign it to the first series of the chart
var rnd = new Random();
var dataSeries = new DataSeries<DateTime, double>();
for (int i = 0; i < 20; i++)
{
dataSeries.Add(new DataPoint<DateTime,double>(DateTime.Today.AddDays(i),rnd.NextDouble()*20));
}
MyChart.Series[0].DataSeries = dataSeries;
The result is the following line chart:
Adding Zooming and Panning to the Chart
So far we have created a static chart. Zooming and panning of
charts are quite common requirements and similar to the Silverlight
version, Visiblox Charts for WP7 supports these from out of the
box. To add zooming and panning we need to set the Chart's
Behaviour to ZoomAndPanGestureBehaviour with the following line of
code:
<charts:Chart x:Name="MyChart" Width="700" Height="400">
<charts:Chart.Series>
<charts:LineSeries/>
</charts:Chart.Series>
<!-- Enable zooming and panning on the chart -->
<charts:Chart.Behaviour>
<charts:ZoomAndPanGestureBehaviour/>
</charts:Chart.Behaviour>
</charts:Chart>
Having added this, the chart can now be zoomed in by pinching,
zoomed out by double tapping and panned by dragging.
Enabling Selection on the Series
Another common requirement with charts and series is support for
user selection of points. This is supported via the same API on
Visiblox Charts for WP7 as it is on the Silverlight version.
Selection of the Whole Series
To enable selection of the whole series, we simply need to set
SelectionMode to Series. When the user taps the line, the
IsSelected dependecy property on LineSeries will now be
changed:
<charts:Chart x:Name="MyChart" Width="700" Height="400">
<charts:Chart.Series>
<!-- Line series with series selection enabled -->
<charts:LineSeries SelectionMode="Series"/>
</charts:Chart.Series>
</charts:Chart>
Selection of Individual
Points
Selection of individual points can also be done. To do so, first
let's display the points by setting theShowPointsproperty
onLineSeriesto true. After this we can enable single point
selection by setting theSelectionModeproperty
onLineSeriestoSinglePoint(or allow selection of multiple points by
setting it toMultiplePoints):
<charts:Chart x:Name="MyChart" Width="700" Height="400">
<charts:Chart.Series>
<!-- Line series with point selection enabled -->
<charts:LineSeries ShowPoints="True" SelectionMode="SinglePoint" />
</charts:Chart.Series>
</charts:Chart>
Now whenever the selection is changed, theSelectedItemproperty
andSelectedItemscollection changes on the series and
theSelectionChangedevent fires.
Here is how the example looks at this point:
Basic Styling of the Chart: Adding Titles, Positioning the
Legend
The plot area of our chart looks decent at this point, however
the surrounding area could use some formatting.
Adding Titles to the Chart, Axes and Series
Setting the title of the Chart can be done by simply setting its
Title property.
The XAxis and YAxis also have a Title property. You may have
noticed, however, that until now we haven't defined any axes: by
default the chart auto - creates these axes based on the data type.
In order to provide titles to them, we need to manually assign an
IAxis instance to the XAxis and YAxis property on the chart:
<charts:Chart x:Name="MyChart" Width="700" Height="400" Title="My First Chart">
<charts:Chart.Series>
<!-- Line series with point selection enabled -->
<charts:LineSeries ShowPoints="True" SelectionMode="SinglePoint" />
</charts:Chart.Series>
<charts:Chart.XAxis>
<charts:DateTimeAxis Title="Date"/>
</charts:Chart.XAxis>
<charts:Chart.YAxis>
<charts:LinearAxis Title="Value"/>
</charts:Chart.YAxis>
</charts:Chart>
Assigning a title to a series in the chart is done by setting
the Title property on its data series. Since in the example we're
creating the DataSeries in code-behind, we need to set this
property there:
var dataSeries = new DataSeries<DateTime, double>() { Title = "Random Values" };
After these modifications our chart looks like the following:
Styling the Title and Positioning of the Legend
There are still a few issues with the chart: the default title
style is too small and the legend is taking too much space on the
right of the chart.
We can change the font size of the title text by setting
theTitleStyleproperty on Chart. This style needs to have a
TargetType of TextBlock.
The legend position can also be set to have it appear inside the
plot area, leaving more space for the data. We can do this by
setting theLegendPositiononChart. Also, by default the background
of the legend is transparent. When displaying it within the plot
area, it might look better to change this background to a brush by
assigning a style to theLegendStyleproperty:
<UserControl.Resources>
<Style TargetType="charts:Legend" x:Key="CustomLegendStyle">
<Setter Property="Background" Value="{StaticResource PhoneBackgroundBrush}"/>
</Style>
<Style TargetType="TextBlock" x:Key="CustomTitleStyle">
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeExtraLarge}"/>
</Style>
</UserControl.Resources>
(...)
<charts:Chart x:Name="MyChart" Width="700" Height="400" Title="My First Chart"
TitleStyle="{StaticResource CustomTitleStyle}" LegendPosition="RightInside" LegendStyle="{StaticResource CustomLegendStyle}">
<charts:Chart.Series>
<!-- Line series with point selection enabled -->
<charts:LineSeries ShowPoints="True" SelectionMode="SinglePoint" />
</charts:Chart.Series>
<charts:Chart.XAxis>
<charts:DateTimeAxis Title="Date"/>
</charts:Chart.XAxis>
<charts:Chart.YAxis>
<charts:LinearAxis Title="Value"/>
</charts:Chart.YAxis>
</charts:Chart>
The modified chart now looks like the following:
Bar Series and Column Series
So far we've used line series to display data on the chart.
Drawing bar or column series is also a frequent requirement and
doing so is not very different from working with LineSeries: only
the series type needs to be changed to ColumnSeries or BarSeries -
and in the case of BarSeries the underlying data source might have
to be changed as the axes get different meanings.
Creating a ColumnSeries Using Data Binding
Using column series follows the same process as working with
line series, we only need to assign ColumnSeries instances to
theSeriescollection on Chart. The data for the series can either be
created manually or with binding to a collection of model items.
We've seen an example of creating data manually, so let's see an
example of creating data via bindings.
First, let's define our model object. In this case the models
will be definitions of GDP data:
public class GDPDataPoint
{
public int Year { get; private set; }
public double GDP { get; private set; }
public GDPDataPoint(int year, double gdp)
{
Year = year;
GDP = gdp;
}
}
To set up data binding, we need to create and assign a
BindableDataSeries class as theDataSeries property of the
series. On thisBindableDataSeries we need to set up the X and Y
value bindings and set itsItemsSource property. Let's define the
series and theirBindableDataSeries's in XAML and set their
ItemsSources in code behind:
<UserControl.Resources>
<Style TargetType="charts:Legend" x:Key="CustomLegendStyle">
<Setter Property="Background" Value="{StaticResource PhoneBackgroundBrush}"/>
</Style>
<Style TargetType="TextBlock" x:Key="CustomTitleStyle">
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeExtraLarge}"/>
</Style>
</UserControl.Resources>
(...)
<charts:Chart x:Name="Chart" LegendPosition="RightInside" Height="440" Width="700" Title="G7 Gross Domestic Product Change"
LegendStyle="{StaticResource CustomLegendStyle}" TitleStyle="{StaticResource CustomTitleStyle}">
<charts:Chart.Behaviour>
<charts:ZoomAndPanGestureBehaviour/>
</charts:Chart.Behaviour>
<charts:Chart.XAxis>
<charts:CategoryAxis Title="Year"/>
</charts:Chart.XAxis>
<charts:Chart.YAxis>
<charts:LinearAxis Title="USD in Billions"/>
</charts:Chart.YAxis>
<!-- Define all 5 series on the chart -->
<charts:Chart.Series>
<charts:ColumnSeries>
<charts:ColumnSeries.DataSeries>
<charts:BindableDataSeries Title="USA" XValueBinding="{Binding Year}" YValueBinding="{Binding GDP}"/>
</charts:ColumnSeries.DataSeries>
</charts:ColumnSeries>
<charts:ColumnSeries>
<charts:ColumnSeries.DataSeries>
<charts:BindableDataSeries Title="Japan" XValueBinding="{Binding Year}" YValueBinding="{Binding GDP}"/>
</charts:ColumnSeries.DataSeries>
</charts:ColumnSeries>
<charts:ColumnSeries>
<charts:ColumnSeries.DataSeries>
<charts:BindableDataSeries Title="Germany" XValueBinding="{Binding Year}" YValueBinding="{Binding GDP}"/>
</charts:ColumnSeries.DataSeries>
</charts:ColumnSeries>
<charts:ColumnSeries>
<charts:ColumnSeries.DataSeries>
<charts:BindableDataSeries Title="UK" XValueBinding="{Binding Year}" YValueBinding="{Binding GDP}"/>
</charts:ColumnSeries.DataSeries>
</charts:ColumnSeries>
<charts:ColumnSeries>
<charts:ColumnSeries.DataSeries>
<charts:BindableDataSeries Title="France" XValueBinding="{Binding Year}" YValueBinding="{Binding GDP}"/>
</charts:ColumnSeries.DataSeries>
</charts:ColumnSeries>
</charts:Chart.Series>
</charts:Chart>
private List<GDPDataPoint> _GDPGermany;
private List<GDPDataPoint> _GDPFrance;
private List<GDPDataPoint> _GDPUK;
private List<GDPDataPoint> _GDPJapan;
private List<GDPDataPoint> _GDPUSA;
public ColumnSeries()
{
InitializeComponent();
// Initalize _GDPUSA, _GDPJapan, _GDPGermany, _GDPUK, _GDPFrance members
InitGdpData();
(Chart.Series[0].DataSeries as BindableDataSeries).ItemsSource = _GDPUSA;
(Chart.Series[1].DataSeries as BindableDataSeries).ItemsSource = _GDPJapan;
(Chart.Series[2].DataSeries as BindableDataSeries).ItemsSource = _GDPGermany;
(Chart.Series[3].DataSeries as BindableDataSeries).ItemsSource = _GDPUK;
(Chart.Series[4].DataSeries as BindableDataSeries).ItemsSource = _GDPFrance;
}
After implementing theInitGdpDatamethod, the deployed example
looks like the following on the device:
Creating a BarSeries
BarSeries is basically a ColumnSeries rotated 90 degrees
clockwise. However, because of this, it's "logical" X axis is the Y
axis, whereas it's Y axis is the X axis of the chart.
Creating a BarSeries is done the very same way a ColumnSeries is
and assigning data is done the same way as well (by assigning a
DataSeriesor a BindableDataSeries to its DataSeries property). The
only difference is that the X and Y values need to be switched from
the ColumnSeries for them to make sense.
So to implement the same example as we did on the ColumnSeries
we'll have to set the chart's XAxis to be a LinearAxis, the Y axis
to be a CategoryAxis and switch the XValueBinding and YValueBinding
values on the BindableDataSeries:
<charts:Chart x:Name="Chart" LegendPosition="RightInside" LegendVerticalAlignment="Bottom" Height="440" Width="700" Title="G7 Gross Domestic Product Change"
LegendStyle="{StaticResource CustomLegendStyle}" TitleStyle="{StaticResource CustomTitleStyle}">
<charts:Chart.Behaviour>
<charts:ZoomAndPanGestureBehaviour/>
</charts:Chart.Behaviour>
<!-- X axis is the LinearAxis, while Y is the CategoryAxis when using BarSeries-->
<charts:Chart.XAxis>
<charts:LinearAxis Title="USD in Billions"/>
</charts:Chart.XAxis>
<charts:Chart.YAxis>
<charts:CategoryAxis Title="Year"/>
</charts:Chart.YAxis>
<!-- XValueBinding and YValueBinding are the inverse of when working with ColumnSeries -->
<charts:Chart.Series>
<charts:BarSeries>
<charts:BarSeries.DataSeries>
<charts:BindableDataSeries Title="USA" XValueBinding="{Binding GDP}" YValueBinding="{Binding Year}"/>
</charts:BarSeries.DataSeries>
</charts:BarSeries>
<charts:BarSeries>
<charts:BarSeries.DataSeries>
<charts:BindableDataSeries Title="Japan" XValueBinding="{Binding GDP}" YValueBinding="{Binding Year}"/>
</charts:BarSeries.DataSeries>
</charts:BarSeries>
<charts:BarSeries>
<charts:BarSeries.DataSeries>
<charts:BindableDataSeries Title="Germany" XValueBinding="{Binding GDP}" YValueBinding="{Binding Year}"/>
</charts:BarSeries.DataSeries>
</charts:BarSeries>
<charts:BarSeries>
<charts:BarSeries.DataSeries>
<charts:BindableDataSeries Title="UK" XValueBinding="{Binding GDP}" YValueBinding="{Binding Year}"/>
</charts:BarSeries.DataSeries>
</charts:BarSeries>
<charts:BarSeries>
<charts:BarSeries.DataSeries>
<charts:BindableDataSeries Title="France" XValueBinding="{Binding GDP}" YValueBinding="{Binding Year}"/>
</charts:BarSeries.DataSeries>
</charts:BarSeries>
</charts:Chart.Series>
</charts:Chart>
The example looks the following when deployed to the phone:
Download the Source Code
The source code for all the above examples can be downloaded
from here:
Visiblox - Basic Charts for Windows Phone 7.zip. To compile the
examples, you'll need to download the latest free version of
Visiblox Charts for WP7 and add the WP7 dll as reference to the
project. You'll also need the Windows Phone 7 Developer Tools
installed.