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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

GRID Header Woes... 1

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi all,
I'm using GRIDs in a number of forms, and VFP sometimes tries to build the Form before the GRID is created properly (so I believe), and when using DYNAMIC BACK COLOR clause, it complains with a string of errors about it being an invalid expression, but if you just ignore these, eventually it displays the GRID properly.
Someone once suggested defining the control source of the GRID in the page/form INIT, instead of in the INIT or Refresh of the control. The problem then is, VFP mangles my headers. I frequently gather more fields in the grid than I display (I guess that's common). But when I put the definition of the control source in the INIT, instead of by GRID control displaying only the fields I want, it squashes a bunch of headers to the left, and then puts one in for every field from the control source.
I tried setting the CONTROLSOURCE values on the GRID itself, and also the text boxes with MYCONTROLSOURCE.MYFIELD1 "bound" to the text box controlsource in the hope that it would only try to display those, but that didn't work either.
Is there a fix/approach for this?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
The simplest thing to avaoid troubles like this is using the forms bindcontrols property. Set it to .F. at ddesigntime, later set it ..

this only helps once, ienot when you want to requery grid source cursors, that needs another approach, but the bondcontrols property helps very good at the initialisation phase, it won' matter much where you set control or rowsource, then, the whole binding only becomes active, when you set thisofrm.bindcontrols = .T., mostly as the last thing in the form init.

That said, the form init always happenslast after inner control inits have already run, otherwise you'd have a real hard time in acting on the controls of a form in form init.

Bye, Olaf.
 
Hi Olaf,
Thanks, so I the form's BindControl property to .F. at design time, and then as the last thing in the Forms' INIT, I set Thisform.BindControl = .T.
And that's all there is to it?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Someone once suggested defining the control source of the GRID in the page/form INIT, instead of in the INIT or Refresh of the control.

It doesn't make sense to set the control source in a Refresh event. The purpose of Refresh is to update the contents of the control according to the control source. The control source must already have been set in order for the Refresh to do its job.

Olaf has a good point regarding BindControls. But, in general, when it comes to setting the control source, it makes sense to do it either at design time or in the form's Init - and certainly no later than the form's Init.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
This form has a PageFrame and 8 Tabs, each of which has from 2 - 8 grid sources. So I'd set all their INIT at the Form level, above the PageFrame INIT?
I've gone round and round with these, and it's really annoying. Particularly because they sometimes (without explanation that I can find) squash all the fields in the CURSOR for the GRID and/or generating DYNAMICBACKCOLOR conflicts, which then resolve at the time it populates (or both). Just trying to work out how to best go about it.
I tried the BINDCONTROLS suggestion, but have been met with a string of errors trying to get that to work.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott, I'm inclined to think there is something more fundamentally wrong here. I've never seen the behaviour you are describing, regardless of how or when I set control sources in a grid.

You mentioned that the grid shows columns for every field in the control source. That looks to me like either you are not setting the RecordSource properly, or the ColumnCount has got clobbered. Are you setting either of those properties explicitly? And, if so, are you doing so at design time or in code?

Also, is the RecordSource a physical table or a cursor? And, if it's a cursor, does the cursor already exist when you load the form? That's important because, if you only create the cursor after you have instantiated the grid, then the existing columns in the grid will be lost - along with their control sources.

If that's the case, then you might need to re-set the RecordSource, RecordSourceType, ContolSource, ColumnCount, and possibly other properties, after you have created (or re-created) the cursor.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
Yeah, I'm working to clean up the way it works here. Since I started the application after coming back after 15 years and remembering how some things worked, and confusing them with others, while getting certain behaviours that I wanted out of it, I see some inconsistencies. So I'm trying to rectify that. I went through all the grids last night, and some that were showing 2 or 3 columns, were defined with 4 columns at design side, though the source control was actually a cursor with maybe 6 - 8 fields. Most of those seem to be behaving now in terms of their columns appearing as they are at design. In every case the grids use a CURSOR as their source, which is dynamically created throughout the interaction of the application.

For instance, The "CONTACTS" for one "COMPANY" will dynamically change as the company grid records are traversed. It will "REFRESH" the source control at the GRID Object level with something like:

SELECT CONTACTFIRSTNAME, CONTACTLASTNAME, CONTACTID, COMPANYID INTO CURSOR CONTACTGRID WHERE COMPANY.COMPANYID = CONTACT.COMPANYID ORDER BY CONTACTFIRSTNAME+CONTACTLASTNAME

(I'm just pulling that off the top of my head, but that's pretty much what that CONTACTGRID cursor will look like). And the intent is, when the company changes, to update the contact grid with just those contacts for that company. I used this trick from Olaf's suggestion, so I'm not filtering tables. (Which I have now fully removed from the application as of last night).

Since this code is the same any time I need it, I put it in the objects REFRESH() clause, and then call that from the PAGE's INIT. (So during INIT at the PAGE, I would issue something like: This.Parent.grdContactGrid.Refresh()

And that creates the CURSOR initially, and then any call to REFRESH() of grdContactGrid (or by cascading refresh of the page or form), it will then update the cursor based on the criteria. This is a kind of "manage the relationships without persistent relationships" that Olaf also suggested to me about 2 years ago. In trying to implement that I may not have done it in the cleanest way... So guidance here on how best to implement this is most welcome. I just thought that a "code maintainability" standpoint, it was best to have only 1 instance of what creates the CURSOR for the gird... so I think my intentions are good, but maybe not the best way to do it?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
If you get errors even though you have form.bindcontrols = .f., then perhaps because of Dynamic-Properties pointing to fields not yet accessable.

What Mike said is true, if you have lots of predefined properties in regard of the controlsources, eg in Dynamic properties, then you might still have the problem your cursors/tables have to be opened already before you set BindControls = .T., not so sure. But keep in mind to only set form.BindControls=.T. once and as last step of the form.init (not per control.init).

I also think its a good idea to set controlsources in the controls themselves in their init, asd you then can do queries etc. This means your controls will be more self contained, encapsulated. It all depends on the encapsulation level you want. The form.init happens AFTER all control inits, so it can orchestrate depndencies between several controls, for example. And if you kept form.BindControls=.F. the form can still do lots of orchestration to fix missing data, etc.

For sure, as Mike also said, you don't set controlsources in Refresh. Using Refresh to do major tasks is no god idea anyway, not only in regard to controlsources. As you learned recently it happens cascading, it also happens from outside, it really is an event, that can also happen, if a user drags a form around, more precise a pseudo event, which for example is called by Winforms events like form paint.#. It should if at all only have code controlling the current display of data. It should neither bind nor requery data or you risc recurring refresh by the refresh code. You might influence enabled for example, you might act on Value of controls, which are not having their controlsource set, and should only do so with caution, eg avoid setting Value to a value it already is to avoid recurrences. The base behaviour will already ensure the current data display is refreshed.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top