Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / GDI+

HBarChart

4.97/5 (91 votes)
10 Jul 2008CPOL10 min read 3   9.1K  
Simple C# control that helps develop charts quickly and print them easily
HBarChart is a simple C# control. It helps you develop your own charts quickly and print them easily.

HBarChartControl_src

Contents

Introduction

HBarChart is a simple C# control. It helps you develop your own charts quickly and print them easily.

Background

A while ago, I created an MFC bar chart control and shared it here on The Code Project. In a discussion below that article, I promised to create a C# version of the same control, and here it is. The only problem is that probably the code looks more like C++ than C#. I hope you'll forgive me; this is one of the few C# codes I've ever written.

Enjoy, and please help me with invaluable notes, bugs reports, ideas, etc. that you think might will improve the quality of this code.

Using the Code

Creating the Chart

To use this control, first we have to add it to a project. You can use one of the following two methods to add it.

Add a Reference to the Project

  1. Copy the BarChart folder, available inside the CPBarChart source folder attached to this article, and all its contents into your solution folder.
  2. Right click on the Solution Explorer of Visual Studio, and select: Add Existing Project, and select the BarChart folder.
  3. Select the project you want to add the chart to and right click on it in the Solution Explorer.
  4. Select Add Reference, select the Project tab of the dialog that opens, and select BarChart, then recompile the solution.
  5. In the Visual Studio toolbox window, you should be able to see a new group named [YouProjectName] Components, inside which the HBarChart item is visible.
  6. Drag the HBarChart component onto any Windows Forms control.

Add the DLL

  1. In the Visual Studio toolbox, right click at the top of a category (like General) and select Choose Items.
  2. In the .NET Framework Components tab, find the Browse button, and using the Browse window, select BarChart.dll.
  3. Now, drag the new bar chart control that's added to the toolbox, on to a form.

You can alternatively drag the DLL to the Visual Studio toolbox.

Chart Background

The background of the chart could be either linear/radial gradient or solid. Gradient uses two colors to draw background of the chart.

To set the background mode, use Background.PaintingMode. It's of type enum, and could be set to either SolidColor, LinearGradient or RadialGradient.

The chart background also has to define the color. The color depends on the current mode selected. If a gradient is selected, there are two colors to be set: GradientColor1 and GradientColor2. If a solid color is your choice of the background, then SolidColor should be identified. The background default mode is radial gradient, and the default colors are: Argb(255, 140, 210, 245) and Argb(255, 0, 30, 90) and could be modified in the CBackgroundProperty() constructor. To change mode or color in your code, use Background property of the chart:

C#
barChart.Background.PaintingMode = CBackgroundProperty.PaintingMode.LinearGradient;
barChart.Background.GradientColor1 = Color.Aqua;

Chart Description

The description is the bottom-most descriptive line of text. In the snapshot, it is: "Hello C# Chart." Its usage is to describe what the chart shows. You can modify its Text, Color, Font, and Visibility.

C#
barChart.Description.Font = fontDialog.Font;
barChart.Description.Text = "Annual coffee usage of c# team.";
barChart.Description.Color = Color.White;
barChart.Description.Visible = true;

Labels and Values

To make the chart more flexible, I made it possible to modify the labels at the bottom of each bar and also the value text at the top of each bar. Please note that while it's possible to modify the labels and the values, they can only be modified as a whole, and it's not possible to do it for each bar separately.

C#
barChart.Label.Font = fontDialog.Font;
barChart.Label.Color = Color.White;
barChart.Label.Visible = true;

barChart.Values.Font = fontDialog.Font;
barChart.Values.Color = Color.White;
barChart.Values.Visible = true;

Instead of the value of each bar, it's also possible to use a percentage. In my MFC version of this chart which was created for a particular purpose, I needed to show the percentage of each value compared to the maximum value. It was considering the maximum value to have 100%. In this chart that is created solely for CodeProject members, I take a more useful, and probably more popular, approach, and the percentage of the value compared to the total values is used, i.e., only a lonely bar will have 100%, and by adding a second bar, each percentage shows the share of the total value the bar takes. Two bars with same values, in this case, each will have 50% of the total value.

C#
barChart.Values.Mode = CValueProperty.ValueMode.Percent;

Border

HBarchart can display a solid border around the chart. Its size and color can be customized.

barChart.Border.Color = colorDialog.Color;
barChart.Border.Width = 5;

Shadows

Two types of shadows can be displayed around the chart; Inner and Outer. Inner shadow starts from inner rims of the bounding rectangle of the chart and moves towards center of the chart, and outer shadow starts from outer sides of the bounding rectangle and move outside. You can set the chart to draw any of them, both of them or none of them.

C#
// Just Inner shadow, could be: Outer, Both, None
barChart.Shadow.Mode = CShadowProperty.Modes.Inner;

You can also set size of the shadow:

C#
barChart.Shadow.WidthInner = 2;

And finally color of the shadow:

C#
barChart.Shadow.ColorInner = Color.Black;

Please note that transparency (alpha) of the color of the shadow is important to have a stronger (darker) shadow or a lighter one.

Sizing

The last customization of the chart is about sizing. The chart has two sizing modes. The Normal mode has no limitation to any drawing. For example, you can change fonts so that parts of texts are out of the chart control, that makes them invisible. The Normal sizing mode along with fonts, colors, texts, BarSize and BarGapSize (white space between bars) makes it possible to create a fully customized chart.

The other possible mode is AutoScale, in which case, the control decides the sizes. It simply tries to fit the chart in its bounding rectangle. Your desired colors and fonts will be used, but the size of the fonts and bars are calculated automatically.

C#
barChart.SizingMode = HBarChart.BarSizingMode.AutoScale;

After customizing the chart to your will, it's time to use it, by adding new values, retrieving, or removing them.

Adding Values (Bars)

To add a new value to the chart, use the Add method as follows:

C#
barChart.Add(
   1600.356,           // A value to be shown at the top of the bar
   "Jan",              // A label under the bar chart
   Color.Aqua);        // Color of the bar

Note that the control uses this color (the last parameter of Add) to create a gradient for the bar, which in my humble opinion is more polished. The gradient's darker color is 100 units darker, so to get best results, please use colors with their (R, G, B) all over 100. E.g., Color.FromArgb(255, 150, 160, 255).

You can alternatively use Items property directly. It's an IList collection.

C#
barChart.Items.Add( new HBarItem(
   1600.356,           // A value to be shown at the top of the bar
   "Jan",              // A label under the bar chart
   Color.Aqua));        // Color of the bar

Removing Values

You can use RemoveAt to remove bars from the control for a specific zero based index.

C#
barChart.RemoveAt(0);  // Removing first value

Or again use Items collection.

C#
barChart.Items.RemoveAt(0);  // Removing first value

Modifying Values

Call ModifyAt to change value of a bar.

C#
barChart.ModifyAt(0, 6250);           // Changing value of first bar

or change values directly.

C#
barChart.Items[0].Value = 6250.1148;  // Changing value of first bar

Inserting a Bar

Call InsertAt or Items.Insert to insert a bar at a specified zero based index.

C#
barChart.InsertAt(
                3,           // Where bar will be inserted
                             // (zero based index of this new bar)
                2650.8265,   // Value of the new bar
                NewLabel,    // Label of the new bar
                Color.Red);  // Color of the new bar

Retrieving Values

To get a value or any other information about each bar, you can call the GetAt method. The method has two definitions: one that returns a double value corresponding to a bar when its 0 based index is given; the other overloaded function returns an HBarItem object. HBarItem is a class that holds all data about a bar, including its value, color, label, the bounding rectangle inside the chart and many more.

C#
HBarItem bar;
if (barChart.GetAt(0, out bar))
{
  // Now we have all bar data
  double dValue = bar.Value;
}

Events

Other than normal set of events for a user control, there are four other events supported by HBarChart: BarClicked, BarDoubleClicked, BarMouseEnter and BarMouseLeave. To handle these events, you can follow one of these two methods:

In Visual Designer

Right click on the chart control on your form and select Properties. At the top of the properties window, select Events button. Then head to Bar Chart section, you should see them. Double click on the title of any event you want to handle.

HBarChart/events.jpg

Handle Events Manually

It's a two step job; first register for the event:

C#
barChart.BarClicked += new BarChart.HBarChart.OnBarEvent(this.On_BarChart_BarClicked);

Second, add an event handler function:

C#
private void On_BarChart_BarClicked(object sender, BarChart.BarEventArgs e)
{
    MessageBox.Show(String.Format("bar #{0} Clicked!", e.BarIndex);
}

Printing

Use the Print method to print the chart.

C#
barChart.Print(true, "PrintDocumentName");

Print receives two arguments. The first one indicates whether the chart should be fitted to paper or should be printed with the same scale of the display. It acts similar to the sizing mode of the chart. The second parameter is the name of the print document. In my to do list, printing is marked as incomplete. There's a class in the BarChart namespace named CPrinter that, together with the Print method of the HBarChart class, is responsible for printing. If you need better printing support, you can modify them.

DataSource

Chart now has a minimal supports for Datasource. It can be connected to a data source. It reads data and responds to changes, but at the moment it's a one way connection and modified chart data will not be mirrored to the datasource. You can look at it as a read only DataSource support.

How chart uses DataSource

At the moment, when you set chart datasource, it expects you to provide a combination of rows and columns that each row displays a chart. For each column, there will be a bar that takes its value from the row. Demo application of this article has a DataGridView control on the form that shows how exactly chart works with data.

Extending Chart DataSource Capabilities

I designed the DataSource in a way that makes it possible to create your own way of reading data and displaying them. HBarChart has a data connection class that connects to datasource and retrieves rows and columns of data automatically. To display these rows and columns in chart, it uses a class that implements IDataConnectionEvents. If you want to be able to interpret rows and columns of data your way, just create a class that implements the interface:

C#
public class CreateChartMyWay : IDataConnectionEvents

Then tell the chart to use your class:

C#
this.barChart.DataSourceManager.DataEventHandler = new CreateChartMyWay();

Doing this, chart will work with data and calls functions that you implemented in your class when needed. It calls functions that are defined in the interface. By implementing IDataConnectionEvents, your class will have these functions:

C#
void DataSource_ItemUpdated(int nRowIndex, int nColIndex);
void DataSource_ItemDeleted(int nItemIndex);
void DataSource_ItemAdded(int nItemIndex);
void DataSource_SelectedRowChanged(int nPosition);
void DataSource_ResetItems();
void DataSource_DataBoundCompleted();

void SetData(object chart, object dataConnection);

Functions starting by DataSource_ will be called when a change occurs in the underlying data.

DataSource_ItemUpdated Will be sent after connection class receives ListChangedType.ItemChanged and indicates a change in a row.
DataSource_ItemDeleted Will be sent after connection class receives ListChangedType.ItemDeleted and indicates a row deleted.
DataSource_ItemAdded Will be sent after connection class receives ListChangedType.ItemAdded indicating a new row added.
DataSource_ResetItems Will be sent after connection class receives any of the following ListChangedTypes: Reset(Many roes changed), ItemMoved(some row indexes changed), PropertyDescriptorAdded(change in schema probably a new column), PropertyDescriptorDeleted(change in schema probably a column removed), PropertyDescriptorChanged(change in schema, a column changed).
DataSource_SelectedRowChanged Will be sent after connection class receives PositionChanged event. It means a new row is Current row of the DataSource.
DataSource_DataBoundCompleted It is called when a connection established to DataSource and rows and columns are populated with DataSource data.

Please note that when DataSource_ItemDeleted is called, data is not actually deleted from rows and columns of connection class, so that you can find data that is to be deleted easily. After the call however, it will be removed.

A final important note: The SetData function is called after your class is instantiated and will give you a reference to both chart (of type HBarChart) and the connection (of type CDataConnection) classes. Chart reference can be used to interact with bars or other chart GUI related stuff and connection to work with rows and columns.

History

  • 2008/06/20
    • First version released
  • 2008/06/24
  • 2008/07/09
    • Support for negative numbers
    • Support for DataSource
    • Items converted to an IList collection
    • Added bar drawing type (subject to change)
    • Added border for the chart
    • Added Shadows for the chart
    • Added Radial Gradient background mode
    • A lot of performance tweaks

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)