For sake of demonstrating what happens with SET REFRESH TO 0,-1:
No timer, no use of Grid.Refresh
nor the Refresh() function:
First, create a test database with a few records in a test table:
Code:
* create temp subfolder for the refreshtest database
Cd Getenv("TEMP")
*Mkdir Refreshtest
Cd Refreshtest
* create database and table
Create Database Refreshtest.Dbc
Create Table Refreshtest (Id Integer AutoInc, Primary Key id Tag id,;
field1 Char(10),;
field2 Char(10),;
lastupdate Datetime,;
rowversion Integer Default 0)
TEXT TO lcProcedures Noshow
PROCEDURE Tablechange
Replace rowversion WITH rowversion+1, lastupdate WITH DATETIME()
RETURN .t.
ENDPROC
ENDTEXT
STRTOFILE(lcProcedures,'refreshtestprocedures.prg')
APPEND PROCEDURES FROM refreshtestprocedures.prg overwrite
ALTER table Refreshtest Set CHECK tablechange()
* Create a few records
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
Append Blank
CLOSE TABLES All
COMPILE DATABASE Refreshtest
CLOSE DATABASES All
Then have a form that just displays that table for editing buffered and with a save button that does a TableUpdate() ignoring conflicts (force update).
To be very clear: For now there is no timer that refreshes anything, the only refresh mechanism working is native VFP behavior by the SET REFRESH setting. And remember, at this stage we check what that means, when you SET REFRESH TO 0,-1 (see form.Load() code) and that means don't refresh after a refresh time, only read from DBF.
Is there a refresh at all? See for yourself. The answer is, as long as users edit and don't save, they each have their version of the table only with their own changes. If one user saves, that will not conflict (nevertheless the case is programmed with a Rollback and TableRevert). The second user will then see changes, but only when changing focus to a changed row. That's native VFP behavior about control sources (and row/record sources too, so in general data binding): The control you focus will read the current data. If you don't make the special REFRESH setting to read from DBF, the local buffer will be used for this gotfocus refresh and the DBF is not read. And that's the default behavior and I think it's the reason people think they write a refresh routine at all. This is actual unnecessary this way.
So this is a minimum solution that'll work, as you see the latest row version and field data when you click on a field. So you edit the most current data. When you are in the middle of editing, the other user might also edit (we're using optimistic buffering, no locks, so that can be changed to disallow parallel editing for the rows that are edited by anyone in any session that locks it, but that's not the major concern in this test, we intentionally allow that to see what happens when a user is in editing and the DBF has new data for the field that's edited).
So to say it in short this is the worst case scenario: User A edits the same field of the same record as User B, one of them saves, the situation is symmetrical, so it doesn't matter, say it's user A. User B would only see that change whenever he next time focusses that field. It currently has the focus, but the native automatic refresh only happens with the GotFocus() event (perhaps already in the When() event) that only happens once when the focus moves to the control, initially, not while you edit.
User B now can also click save and will overwrite User A's change without error (as the save routine uses TableUpdate() with the force option, you can change that).
Check it out for yourself (start VFP two times on the same PC, put the windows side to side and start the second PRG in both VFP IDEs). If you already did, I think you'll confirm this is the behavior you also see. And that means your concern of an edit being overwritten will not happen. If you had a timer that refreshes the grid, that will change, sure, but you don't need to have that in this version.
The disadvantage is, a user really just sees the current data when changing to a row. At that moment he might already look to the keyboard clicks and doesn't notice the refresh this causes. That's the risk of it. Also it would of course be nice if you could see changes earlier, in rows you don't (yet) edit, but might edit next. You could see another user already cares for them and don't interfere. That's not happening here and that will need an active refresh method. Which means I call this automatic refresh we have so far a passive refresh. As nothing happens without an action of the user to click on a record.
Before introducing a timer to do something (or modifying your timer code) we could check what a change of SET REFRESH does. So let's next try SET REFRESH TO 1,-1. That means every second the cached table data will be refreshed, but will the grid refresh? Spoiler: No.
Yes, I hate spoilers, too, but that's the reason you still have a legitimation for something on top of this automatic just in time refresh, as it's good enough, but has one aspect confusing users. They'll ask the question why does data all of a sudden change when I want to edit it? Even when they realize that the data may have been that for a while and they just see it by clicking on it. Users by default think what they see is current, especially on a computer display. Paper might have outdated data, but not a display? But a form, even directly bound to a DBF, isn't a file view, it's only a view of the data as it was initially read. That's not only happening with SQL. The just in time refresh is already more than a usual client/server architecture can provide. I think many VFP developers are proud of this already, as it makes working with data so easy and adds to the feeling of having the best database backend. It has it's downsides, too, especially if you want to perfect it to be even more to the point of a viewer of the data as it is right now.
One of the few really live view of data I know works quite well is google docs online multi user sessions editing in parallel you can see multiple text cursors and see live changes. You don't know how complicated that is, you have an idea as you already think know the problem of getting a refreshed field while you edit it.
Okay.
I'll start continuing my experiment, but might only post it tomorrow. This already is enough for now to let it sink in, right? If you encounter any problems with the code so far: I'm here foor the next 1-2 hours for sure and could react quickly.
Chriss