Introduction

This article presents step-by-step instructions on how to create a simple bar chart with WPF, using C#. You could substitute C# with any other .NET language of your choice. This article is only intended as a learning exercise. The chart is not of professional quality. There may be bugs here and there, but there are also a few good points. I'll keep improving this code over a period as I incrementally build my WPF skills, and hope to post more articles.

The current code is written to work with XML data. You could replace this with minimum effort. In a later article, I will try to improve upon this and make this more generic as the intent of this article was just to get hooked on to the charting capabilities of WPF using basic elements.

I am thankful to a few of my colleagues in my present company [not naming them as I haven't taken their permission], who in some form or the other enriched my understanding (whatever little I have) of WPF.

Background

This article assumes prior knowledge of C# and WPF. In case you are interested in learning about WPF, there are some excellent resources available on The Code Project. A few of them are listed below:

Drawing the Chart

The main drawing activity happens in the Generate method. This mind-map shows the important activities for drawing a chart:

Add chart controls to setup the basic layout.

Set up chart area.

Get the data source.

Check if data is present. If not, draw empty chart.

Calculate the max Y-axis value. This is required for proper scaling.

Draw the X-axis.

Draw the Y-axis.

Draw the X-axis label.

Draw bar for each data value.

Draw the legend.

///<summary>/// Creates the chart based on the datasource.
///</summary>publicvoid Generate()
{
// Reset / Clear
legends.Clear();
chartArea.Children.Clear();
// Setup chart elements.
AddChartControlsToChart();
// Setup chart area.
SetUpChartArea();
// Will be made more generic in the next versions.
DataTable dt = (DataSource as DataSet).Tables[0];
if (null != dt)
{
// if no data found draw empty chart.
if (dt.Rows.Count == 0)
{
DrawEmptyChart();
return;
}
// Hide the nodata found text.
txtNoData.Visibility = Visibility.Hidden;
// Get the max y-value.
// This is used to calculate the scale and y-axis.
maxData = GetMax(dt);
// Prepare the chart for rendering.
// Does some basic setup.
PrepareChartForRendering();
// Get the total bar count.
int barCount = dt.Rows.Count;
// If more than 1 value field, then this is a group chart.
bool isSeries = ValueField.Count > 1;
// no legends added yet.
bool legendAdded = false; // no legends yet added.
// For each row in the datasource
foreach (DataRow row in dt.Rows)
{
// Draw x-axis label based on datarow.
DrawXAxisLabel(row);
// Set the barwidth. This is required to adjust
// the size based on available no. of bars.
SetBarWidth(barCount);
// For each row the current series is initialized
// to 0 to indicate start of series.
int currentSeries = 0;
// For each value in the datarow, draw the bar.
foreach (string valField in ValueField)
{
if (null == valField)
continue;
if (!row.Table.Columns.Contains(valField))
continue;
// Draw bar for each value.
DrawBar(isSeries, legendAdded, row,
ref currentSeries, valField);
}
legendAdded = true;
// Set up location for next bar in series.
if (isSeries)
left = left + spaceBetweenBars;
}
// Reset the chartarea to accommodate all the chart elements.
if ((left + BarWidth) > chartArea.Width)
chartArea.Width = left + BarWidth;
// Draw the x-axis.
DrawXAxis();
// Draw the y-axis.
DrawYAxis();
// Draw the legend.
DrawLegend();
}
}

Drawing the Bar

The DrawBar() function handles the rendering of each bar. The bar, in our case, is represented by a rectangle object.

Feedback

The above code is a result of my learning WPF. In no means is this code optimized or perfect in every sense. The idea was to just post what I learned so that others may benefit from it. Please provide constructive criticism as this will help me improve my WPF skills and help me write better articles.

Points of Interest

Some of the things which I learned while developing this hobby code are outlined below:

Understand basic chart drawing

Understand basic WPF layout

How to draw a smart axis label

Tooltip and templating (under development)

Adding legends

Zoom-in/Zoom-out features

Development Ideas

Highlighted below are some of the objectives which I would like to tackle in my next article:

Make the chart component reusable

Support any datasource

Enhanced tooltip templating

Drilldown features

In-built chart filtering capabilities

I may not be able to meet all the above intent in one go, but would take it up incrementally over a period of time.

Credits

All credits to CodeProject WPF article writers as I am learning mostly from their articles.