Expert Software Company : News

sâmbătă, 29 mai 2010

Grid Reconstruction

1. Grid reconstructs self always when RecordSource alias closed. If this is a view, reconstruction usually do not happens when you requery view, however, there are some reports that this could happen, so test carefully your application to see if view requery do not cause the grid reconstruction. 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.

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.

* 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.

With views, this is the most common situation because grid used often to display data dynamically, so it requires to be refreshed by another data. REFRESH() command for view does not cause reconstruction, however it could be used to refresh data only record-by record. For real refresh requery is needed. The main mistake here also is just requery view and leave it as is. Its a single command, so programmers often do this in many places without aware that they're doing something bad. After that, when reconstruction behavior observed for some view requery, programmer starts to find all places where this view is requeried. It might be in many places across forms and classes that starts to be a big problem. Tip: put data requery (and all other actions with data) in one place - class method or function. Always suggest that any data function might require in future some additional code, even when it is as simple as a requery of view. This way you will help youself to save a time to find all places where some action done with data in case you need to modify something. Grid reconstruction is one of such cases that you cannot avoid when it appears.

NEW!
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:

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:
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.

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 with grid, 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.

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#721

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!

Niciun comentariu:

Trimiteți un comentariu