Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Shaun E on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Grid reconstruction behaviour and how to avoid it

Classes and Objects

Grid reconstruction behaviour and how to avoid it

by  TomasDill  Posted    (Edited  )
Have you ever found a situation when your grid don't want to behave as you directed in design time? Custom controls in columns lost? Code of columns, headers or controls event not running? Read this FAQ then.

Grid reconstruction behavior is a complete removing of all grid's controls and columns and creating them again using default VFP controls. This cause lose of all methods, property settings and objects in columns and all column objects, column control to display and edit data is reset to the default text control, custom headers lost. It happens in following cases.

1. Grid reconstructs self always when RecordSource alias closed. If it is SQL statement, it happens when you assing anotehr SQL statement or just close alias used to store results of the query for grid. It also happens when you use SQL Pass-Through to query data into the alias that used as a record source of grid. PACK command, for example, cause re-opening of the table that cause recostruction.

To avoid reconstruction when refreshing grid's record source, you require to assign empty string (not a one space - " ", but empty string - "") to the Record source before any of grid's record source refresh actions described above. If you already do that, just check your code if you do that in correct order or any other thing does not spoil the correct order of refreshing process. After refresh assign record source to grid again. Reconstruction in such case does not happen, however, another problem arises - all grid's columns re-bound to the control sources automatically by the phisical fields order. Following is a sample of how to fix that by little of code.
Code:
* remember control sources in the column's comment field
with {grid}
  local nColumnIndex
  for m.nColumnIndex = 1 to .ColumnCount
    .Columns(m.nColumnIndex).Comment = .Columns(m.nColumnIndex).ControlSource
  endfor
* prepare grid for refreshing of the Record Source
  .RecordSource = ""
endwith
* do refreshing of the record source
...........
with {grid}
* restore record source
  .RecordSource = "{RecordSourceName}"
* restore control sources
  for m.nColumnIndex = 1 to .ColumnCount
    .Columns(m.nColumnIndex).ControlSource = .Columns(m.nColumnIndex).Comment
  endfor
endwith

In above code {grid} is a reference to the grid object, {RecordSourceName} is a name of the alias used as a record source or SQL statement.

Significant note: do not do any refreshing of the visible controls or grid on the form after statement 'RecordSource=""' and up to full restore of the control sources. Otherwise you will meet a problem with the error message like 'Type is not supported by control' in case you use costom controls in grid columns. This because after spoiling control sources incorrect field types might be used for column. For example, when you have a checkbox in the grid column, after refresh of record source column with checkbox often get a character field control source. If then you refresh a grid, you will get an error or something weird might happen like crashes or bad refresh.

Another approach to prevent grid reconstruction is to use BeforeRowColChange event of the grid.
BeforeRowColChange event is fired each time when grid is going to be reconstructed. It happens in any case include when grid alias closed, view requeried etc. despite grid visibility, focus and grid configuration. The most amazing is that putting NODEFAULT in this event for duration of data changes prevents grid reconstruction at all! Example:

Code:
thisform.GridRefreshing = .T. && tell all grid controls that grid data going to be requeried
... do data requery
thisform.Grid.RecordSource = thisform.Grid.RecordSource
thisform.Refresh && or grid refresh
DOEVENTS
&& after this moment grid stops to reconstruct self
thisform.GridRefreshing = .F.

In the BeforeRowColChange of grid class event put following:
Code:
if PEMStatus(thisform,"GridRefreshing",5) AND thisform.GridRefreshing
    nodefault
    return
endif
You can put above code in the grid class so this functionality will be generic.

The best thing is that this method do not require to organize restoring of the control sources of all columns. However, sometimes ot is require to set focus outside of grid and set it back to grid, because the current cell in grid might show asterisks ('*******') when avoiding reconstruction this way.

Unfortunately, there are no way to know the reason why BeforeRowColChange event is called to distinguish if it is called for recornstruction or it is called for movement between cells or some other actions with grid. Just use a flag for that as in the sample. You can, of course, catch the events that occur before the BeforeRowColChange, but this require a lot of things to do: Catch the KeyPress event on the form with KeyPreview=.T. (that makes an approach not generic), put a transparent cover shape over the grid to catch mouse events or sue MROW() and MCOL() functions to see whene mouse is clicked etc.

2. Reconstruction happens when grid is initialized and record source property is empty or record source does not exists (alias is not open). In this case grid reconstructs self and use current alias as a record source if opened (or keep self empty if no alias opened in current workarea, but all columns destroyed anyway). If you need to open record source in some other event than Load event of the form (before grid initializing), use following technique.

In the Load event of form create an empty cursor with the same structure as a record source for grid; record source property of grid should use that empty cursor. Then, when you open real data, assign empty string to grid's record source, open data and then assign again real data alias as described in the paragraph 1.

For case you need a generic container class with grid for many forms when record source opened by this class only, put an invisible custom control that will create empty cursor in its Init event. However, assure that Init event of that control fires BEFORE Init event of the grid, otherwise reconstruction will happen. You can change Z-order of controls in container in class and this should also tell VFP the oder of Init event firing.

3. Grid reconstructs self when column count changed to 0 or -1. I hope you never do this, do you? ;)

4. Grid reconstructs self when alias used as record source and it goes out of scope. This usually happens when record source assigned in one data session, but grid really initialized in another data session, so when it tries to refresh self, another data session used where record source does not exists. This may occur also in other situations when programmer uses data sessions switching extensively.

Another popular approach to eliminate the grid reconstruction problem is dynamic grid creation. Make a custom grid class with all your code and columns definitions. When requery data, remove grid control from form, requery data, then add grid to form again in run-time. This requires to handle first adding of grid, set some properties of grid etc etc.

You can also create grid object in run-time and populate it by the custom controls using code. (Note that you can define custom header class.) However, after grid reconstructs self, you need to add these custom controls to grid again. This approach used in case when grid reconstruction is not avoidable, for example, in the administrative programs - to show any table content in the same grid, but also allow some functionality in grid like editboxes to see memo fields, sorting by click on headers etc. The sample code of creating grid in run-time and add some custom controls you can see in the FAQ "How to put grid on the form programmatically".

I hope this help you to figuire out a problem with your grid. Good luck and don't be frustrated, grid is very good control in VFP with no analogue!
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top