Introduction

This article provides a surprisingly efficient way of displaying real-time data changes in an Excel-style grid. When choosing to display data in a grid pattern, your natural first-choice would be to use a DataGrid control bound to a DataSet. However, I thought I'd try using a ListView control for the same purpose.

The aim was to provide a lightweight control that requires very little memory and processing power and has very small latency under heavy load. The simple definition of latency is the time delay between the moment something is initiated and the moment its first effect begins. For software this is usually measured as the time between the raw data arriving and the results being displayed on the screen.

Background

Q. Why does it matter how much processing power is being used?

A. Developing software for the financial sector isn't for the faint-hearted. Huge sums of money can be made or lost in a very short space of time and for the developer, this means that the software has to be reliable, robust and above all, very fast. One of the hallmarks of well-written financial software is very small latency.

The main cause of problems is due to the sheer volume of data that needs to be processed and analysed as quickly as possible; a corporate profit warning, an unexpected change in interest rates or a terrorist attack will all send a shockwave around the financial markets of the world and result in an overwhelming amount of data being generated. This is known in the trade as a 'Fast-Market'.

The data is usually received via data-streams from financial exchanges like Dow-Jones, Liffe and Eurex and this is an obvious case for multi-threaded processing being used to boost performance. However, the data also needs to be displayed in an informative way and this requires the use of a GUI - a notoriously single-threaded process. In poorly designed systems this can lead to a fatal bottleneck with the actual rendering of the data taking up far too much of the available processing power. The result will be out-of-date information being displayed to the user as current data is backed-up awaiting display.

If more processing power is being used by the GUI, it will mean that there's less processor available for the data analysis algorithms that are busy crunching data in the background.

The Example Application

The example application is a bit contrived but demonstrates a typical scenario for which a real-time data grid is required. A random data feeder is used to simulate market data arriving on multiple threads. The speed at which the data arrives can be controlled by using a sliding scale from 0 (No-Data) to 10 (Fast-Market). There are also a couple of buttons that will provide a sudden burst of data that will flood the grid with update events all at once, something that is quite common in the financial markets whenever key data is released.

The remaining controls are all concerned with the appearance of the grid itself and are meant to illustrate the effect on performance that the different painting effects have.

Design Overview

This article assumes a working knowledge of .NET programming with C# and a familiarity with the standard windows ListView control. The control of interest is unimaginatively named ActiveGrid and is little more than an owner-drawn ListView control with the View property hardwired to Details.

The ListView control, along with its Items and SubItems, have all been sub-classed so that some of the key functionality can be either intercepted or overridden. A more obvious candidate would be the DataGrid control but for my money, the ListView has always looked more appealing than a DataGrid from an aesthetic point-of-view and this was my main reason for using it. It comes with some very useful built-in functionality and it would be a shame to lose this.

Main Classes

System.Windows.Forms Base Class

Derived Class

ListView

ActiveGrid

ListViewItem

ActiveRow

ColumnHeader

ActiveColumnHeader

ListView.ColumnHeaderCollection

ActiveGrid.ActiveColumnHeaderCollection

ListView.ListViewItemCollection

ActiveGrid.ActiveRowCollection

ListViewItem.ListViewSubItem

ActiveRow.ActiveCell

ListViewItem.ListViewSubItemCollection

ActiveRow.ActiveCellCollection

ActiveColumnHeader Class

This class is responsible for the presentation of content in both the column header and all of the cells belonging to the column. In addition to all of the existing properties of the System.Windows.Forms.ColumnHeader, a new category of properties has been created to handle the appearance of the cells:

// Category: Cell Appearance
//// Horizontal alignment of the text in all cells belonging to this column
Boolean CellHorizontalAlignment;
// Vertical alignment of the text in all cells belonging to this column
StringAlignment CellVerticalAlignment;
// Format specifier for the text in all cells belonging to this column
String CellFormat;
// Show or hide the value of zero
Boolean DisplayZeroValues;
// Allows the rows to be sorted based on the contents of the cells belonging to this column
SortOrderEnum SortOrder;

ActiveGrid Class

This class is the main control that hosts the collections of both columns and rows. The System.Windows.Forms.ListView class from which it is derived can be displayed in five different view-types but only the Details setting makes any sense if you want to display a grid style view. Consequently, this property is hardwired in the derived class. Additional key properties are provided in two new categories:

// Category: Appearance Alternating Row
//// Draw alternating backgrounds
Boolean UseAlternateRowColors;
// Background color of alternate rows in the list
Color AlternatingBackColor;
// Draw backgrounds using a gradient
Boolean UseGradient;
// Direction of the background gradient
LinearGradientMode LinearGradientMode;
// Start Color of the alternating background gradient
Color AlternatingGradientStartColor;
// End Color of the alternating background gradient
Color AlternatingGradientEndColor;
//// Category: Flash Behavior
//// Flash the cell when its contents are changed
Boolean AllowFlashing;
// Draw gradient backgrounds for flashed cells
Boolean UseFlashGradient;
// Fade-out effect for flashed cells
Boolean UseFlashFadeOut;
// Length of time in milliseconds that a cell remains in the flashed state
Int32 FlashDuration;
// Colour of the text when a cell is in the flashed state
Color FlashForeColor;
// Colour of the background when a cell is in the flashed state
Color FlashBackColor;
// Font used when a cell is in the flashed state
Font FlashFont;
// Start Colour of the background gradient when a cell is in the flashed state
Color FlashGradientStartColor;
// End Colour of the background gradient when a cell is in the flashed state
Color FlashGradientEndColor;
// Direction of the Background gradient for flashed cells
LinearGradientMode FlashLinearGradientMode;

ActiveRow.ActiveCell Class

This class is where most of the new functionality is to be found and mainly concerns the presentation of the cell contents. There are three text regions in every cell:

The centre text-string is aligned according to the CellHorizontalAlignment setting in the column header. Each of the three text regions has its own user-defined colour, font and string. All aspects of the cell's appearance can be modified at run-time immediately prior to re-painting it. This enables individual cells to be color-coded according to the type of change being made. For example, if the value is increasing it can be drawn in blue, whereas if the value is decreasing it can be drawn in red.

Other Functionality

Columns can be moved at run-time

Rows can be sorted by column by clicking on the column header

The row header behaves like a LinkLabel

Conclusion

What is presented here is an alternative approach to the standard DataGrid that could easily be used under the right circumstances. It's very efficient and can be easily extended to suit your own business requirements.

It also emphasises the relationship between GUI complexity and processor requirements. There is an ever increasing tendency to make software that is as good-looking as possible but unfortunately all of this 'sex-appeal' comes at a price. As a general rule, the more plain and boring your user interface, the better your performance will be. This is important to bear in mind if the processing power could be better used elsewhere. Of course, this can always be offset by better hardware. A top-of-the-range processor and graphics card will serve you well in this example, which is all very well if your budget can run to it. If it can't, you'll just have to rely on good, old-fashioned coding that gets the job done as efficiently as possible.

History

29 September 2007: Release 1.0.0.0 of ActiveGrid

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.