MFC Grid manual

Introduction to the grids. Existing solutions.

In this article we will describe existing solutions presenting data in grids. There are following kinds of grids:


Grids working in the real mode (without virtualization)
Grids with virtualization
Data-table like grids
Grids with data binding


Grids working in the real mode (without virtualization)

These grids have an internal data structure presented by a list of rows. Each row is presented by a list of items shown in grid cells. Generally, these cells are accessed by referencing to the row and column. The interface may look like:

grid.Rows[index][column] = "something";

For example, CListCtrl of MFC library offers the following syntax:

LVITEM lvi;                     //Corresponds to a grid row 
lvi.iSubItem = 1;               //The column index
lvi.pszText = _T("something");
grid.SetItem(&lvi);

where lvi corresponds to a row, and lvi.iSubItem - to a column. As you see, this looks like a bi-dimensional array, where all data is stored as formatted strings. When you call grid.SetItem(...), behind the grid calls Invalidate() with cell dimensions, and at reception WM_PAINT it draws "something" string in the right position. This behaviour is transparent for the programmer.

There are few advantages of this mode. The single advantage is that it is easy.

Limitations of this design:

Grids with virtualization

The main idea of this approach is based on the feature of Windows operation system where the painting mechanism is divided in two parts. If you want to design something somewhere, you should first call Invalidate() function of CWnd with specified bounds. Windows cumulates rectangles, and then it outputs WM_PAINT message. By receiving this message, the control can draw text, lines, etc in requested bounds. All grids use this mechanism directly or indirectly. In case of virtualization the grid does not keep formatted data, but requests it at painting time.

Advantages:

Main problems:

Data-table like grids

The next step to simplify programmer's life is data table-like grids. The main approach is to create an intermediate level presented by a data table. Such table contains bi-dimensional array (rows & columns) which can be bound to the grid. The main difference between the real-mode and table-like grids is that the table contains an array of non-formatted values (long, double, etc... but not formatted strings). Data are presented through formats that transform these values into strings. One or multiple grids can listen to notifications from the same table and automatically update the visible content.

Access to data looks as follows:

table[row][column] = my_value

Advantages:

Difficulties:

Grids with data binding

This is a real revolution in the grid design. It permits to greatly simplify the application by separating business data from their presentation. Data-table approach limits data organization and adds an intermediate level between business data and its presentation. What is new in this mechanism? Each object may have some data and functions that get or manipulate this data. Such object may be directly inserted into the grid and the functions of this object can give information for cells. That means that functions may correspond to columns. The mechanism that enables retrieving data from the object by calling its functions is called data binding. If the object offers a notification mechanism, and the grid implements it, programming becomes very easy. Thanks to it, you will have a clear business model and after binding you can forget that your object is presented somewhere. If you call set functions of your object, each grid that is bound to your data will update, sort, filter, etc... your data. You don't need to worry where it is presented.

Advantages:

General problems:

We offer the solution based on the data binding thread-safe mechanism. This means that the grid can receive data updates from any thread and perform synchronization itself. Moreover, our solution is not only thread-safe, but also dead-lock free because the data updating doesn't locks the calling thread.