>I'm not really sure why I wanted to build the cursor on form load versus in the listbox in the first place...
It's a widely used and accepted way to load data for all form controls before showing a form, so there are no quirks, especially with grids. As Dan said that also happens, when you query a cursor again and a good strategy is to keep the original cursor alive, Do a query into a secondary alias name, zap the original (which keeps it alive, just not it's data) and append new data.
Another elegant solution in that aspect is a view, which you can requery bby REQUERY("viewname") and that would work with all kinds of controls, too. But views in themselves are limted compared to how you can act on tables and cursors on top of a first query, eg do several queries for an end result, update, scan etc. the cursor. All that can of course also be done with a view cursor, but only the view cursor is backlinked to underlying tables and that limits you a bit.
I always think of rowsourcetype 3 or 4 being too tightly coupled to a DBF data backend. I never worked with .qpr files, which I believe are simply PRGs with the queries, the query designer created. I don't know, whether you can add code in there, eg making a remote connection, etc.
Here's a way you could work with controlspecific aliases and keep the update logic encapsulated, when designing your own control classes:
Add a property "rowsourcealias" and set that instead of rowsource at design time, to the usual alias you want to bind to. In Requery of eg the listbox you can then do
Code:
If This.RowsourceType = 2 And Used(This.rowsourcealias)
Local lcRowsource
lcRowsource = "crs_listbox_"+This.rowsourcealias
If NOT Used(lcRowsource)
* Initialisation phase, first time the control specific rowsource cursor is created:
Select * From (This.rowsourcealias) Into Cursor (lcRowsource) Readwrite
This.Rowsource = lcRowSource
Else
* Update phase, copy over data
Set Safety Off
Select (lcRowsource)
Zap In (lcRowsource)
* ZAP would be sufficient after SELECT (lcRowsource), I just like to be really safe in what I ZAP
* Eg think about adding a breakpoint, debugging, inspecting data, then press F8 and ZAP whatever you last viewed.
Set Safety On
Append From Dbf(This.rowsourcealias)
EndIf
EndIf
Dodefault()
In the end you set the rowsourcealias to "yourtable" and the controls real rowsource will be "crs_listbox_yourtable".
You can keep all your data retrieval code as is, just do Control.Requery in the initialisation and every time, you want to display new data, after you queried it into a cursor or table named as usual. This will handle creating and maintaining a secondary cursor with a name prefix "crs_listbox_". You may come up with other prefixes to ensure it has no collision with any names you normally use for aliases.
Checking This.RowsourceType is 2 ensures, that this only has an effect in controls bound to aliases, not any controls driven by arrays or other sources, Used(This.rowsourcealias) makes sure the data to copy into the control specific cursor exists.
Bye, Olaf.
PS: There is a side effect on present code, of course, as the name of the cursor bound to the control really changes. Eg checking the active/selected record via alias.id, you now instead have to check crs_listbox_alias.id or Select (control.rowsource) and then read id (just the field name) or set lcAlias = control.rowsource and work with eval(lcAlias+".id"). So that change comes with a price.
Anyway, it's also a good practice generic code you write for controls does not include specific database/table names, but take them from the control properties or other meta/configuration data. It's another aspect of write once for reuse.