Virtual Grids
There are two ways to populate the grid.
1. Store the data inside the grid, using CGXGridCore::SetStyleRange() or CGXGridCore::SetValueRange().
2. Dynamically bind or tie the grid to data such as a database, a live data feed, or an external data structure in your application.
The second method is known as Virtual Binding. When operating in virtual mode, the programmer can supply both the data and the grid dimensions dynamically. This section discusses in detail the architecture that enables virtual mode in the grid.
Supplying Data
Before the grid object can prepare itself for drawing, the dimensions of the grid must be known. In Objective Grid, those dimensions are supplied through CGXGridCore::GetColCount() and CGXGridCore::GetRowCount(). In a virtual grid, you will need to override one or both of these, depending on your implementation. The base class versions of these methods simply return the values stored in the grid object.
NOTE >> GetRowCount() and GetColCount() are used extensively to validate values within routines. In addition, because HitTest() is called repeatedly on every mouse move and because this method touches a lot of grid code, including GetRowCount(), it is not unusual for GetRowCount() to be called thousands of times in a short period of time. Because GetRowCount() and GetColCount() are called quite often, your overrides of these methods are not an appropriate place to do extensive calculation.
Once the dimensions are known, the grid object determines which cells need to be redrawn. For each cell that needs to be redrawn, the grid object composes its cell style. This is done by calling CGXGridCore::ComposeStyleRowCol().
Recall from the styles architecture discussion that ComposeStyleRowCol() calls GetStyleRowCol() multiple times. The CGXGridCore implementation for GetStyleRowCol() simply returns the internally stored styles. To supply data or attributes at run time, the programmer can override GetStyleRowCol().
 
// Supply data (and other formats) from external
// data source
BOOL CVirtGridView::GetStyleRowCol(ROWCOL nRow,
ROWCOL nCol, CGXStyle& style,
GXModifyType mt, int nType)
{
BOOL bRet = CGXGridView::GetStyleRowCol(nRow, nCol,
style, mt, nType);
if(nType >= 0)
{
if(nCol != 0)
{
// Get value from external data source
style.SetValue(GetValueFromExternalDataSource(nRow, nCol));
 
// If negative no. then return
if(gxttof(GetValueFromExternalDataSource(nRow, nCol)) < 0)
style.SetTextColor(RGB(255,0,0));
}
}
return bRet;
}
The first thing this method does is call the base class version. This is to populate the style parameter with any internally stored attributes or data. You should always give the grid object first crack at filling the style. If you set attributes in the style object and then call the base class, you run the risk of losing your original settings.
Next the method checks to see if nType is greater than or equal to zero. This is an important step. Remember that ComposeStyleRowCol() makes several calls to GetStyleRowCol(). One is for the cell-specific style (nType >= 0), and subsequent calls are for base styles (nType = -1). Using this check, you can supply cell-specific or base style attributes dynamically.
Inside the if statement, the value is set using:
style.SetValue(GetValueFromExternalDataSource(nRow, nCol));
GetValueFromExternalDataSource() is some arbitrary method that returns the value for a given row and column. It is not an Objective Grid method, only a function name made up for this discussion. Notice that SetValue() is called on the style object passed in the parameter list. This call sets the value in that object and not to any styles stored internally in the grid. This means that every time the style is composed, this override will fetch and set the data. No data is stored in the grid object.
On a side note, the style parameter is an instance of CGXStyle created externally to the GetStyleRowCol() method. It is passed by reference to GetStyleRowCol(). GetStyleRowCol() then populates the object using internally stored styles or virtually as we have done here. It is important to realize that this style object is temporary. Any changes made to it are not stored in the grid object, so it is not possible to “set-and-forget” style properties for a grid cell like you can for a non-virtual grid.
The second chunk of code in the if statement:
 
// If negative no. then return
if(gxttof(GetValueFromExternalDataSource(nRow, nCol)) < 0)
style.SetTextColor(RGB(255,0,0));
sets the text color if the cell’s value is negative. This is an example of setting attributes virtually. It follows the same guidelines as virtual data.
The discussion thus far assumes that you only have plain data in your external data source and that attributes need to be set on a per-cell basis. You can also supply base style formatting by checking for nType = -1. For example:
 
if(nType >= 0)
{
...
}
else if(nType == -1)
{
if(nCol != 0)
// Get font for the column from external data source
style.SetFont(GetFontForColumn(nCol));
}
This code sets a column-wide font dynamically.
Storing Data
Just as you can set attributes or data for a grid dynamically, you can retrieve attributes or data from a grid dynamically. The key method for this process is StoreStyleRowCol(). StoreStyleRowCol() will be called every time an attribute or value needs to be stored in the grid object. This includes user changes to the cell data. You can override StoreStyleRowCol() to divert those changes to your external data source. Here again, you should call the base class to allow the grid object to store those attributes that you are not storing externally.
 
// Store the changes made in the grid into your
// external data source
BOOL CVirtGridView::StoreStyleRowCol(ROWCOL nRow, ROWCOL nCol,
const CGXStyle * pStyle, GXModifyType mt,
int nType)
{
if(nType == -1)
{
return CGXGridView::StoreStyleRowCol(nRow, nCol,
pStyle, mt, nType);
}
else if(nType >= 0)
{
if(nCol != 0 && pStyle->GetIncludeValue())
{
StoreValueIntoExternalDataSource(nRow, nCol,
pStyle->GetValue);
return TRUE;
}
}
return FALSE;
}
Usually, the value is the only modifiable style attribute that you supply in GetStyleRowCol(). As demonstrated above, it is possible to supply other attributes dynamically. If you would like to store those attribute changes, you can do so in the StoreStyleRowCol() override.
 
if(nCol != 0 && pStyle->GetIncludeValue())
{
...
}
else if (nCol != 0 && pStyle->GetIncludeFont())
{
StoreFontIntoExternalDataSource(nRow, nCol, pStyle->GetFont());
return TRUE;
}