I think I have found the answer after hacking away it this for 6 hours...

[code]Object oTimer is a DFTimer

Set Auto_Activate_State to True

Set Timeout to 100 // fire often
Property Integer piRow // remember last row we worked on

Procedure OnTimer Integer iwParam Integer ilParam
Forward Send OnTimer iwParam ilParam
RowID riID riOldId
Integer iRow iColumn iCurrent hoNav
Variant vNav
Boolean bOk
tDataSourceRow[] DataSource
Move 0 to iColumn

If (OPERATION_MODE=0) Begin // don't do this if the user is currently in a DDO operation
Get piRow to iRow
// get the raw data
Get pDataSource of (phoDataSource(oDbCJGrid1)) to DataSource
// make sure our last row count isn't out-of-bounds
If (SizeOfArray(DataSource)<=iRow) Move 0 to iRow // start from top again
If (SizeOfArray(DataSource)>iRow) Begin // make sure it has at least one row
// refind the row and see if the data changed. hold the current rowid so we can reset it
Move DataSource[iRow].riID to riID
Move (GetRowID(SOMETABLE.File_Number)) to riOldId
Clear SOMETABLE
Move (FindByRowId(SOMETABLE.File_Number, riID)) to bOk
If (SOMETABLE.SOMEFIELD<>DataSource[iRow].sValue[iColumn] ) Begin
Move SOMETABLE.SOMEFIELD to DataSource[iRow].sValue[iColumn]
// Move the datasource back
Set pDataSource of (phoDataSource(oDbCJGrid1)) to DataSource
// Here is the magic. We get the current row and then move to itself.
// The nice part is that this doesn't do any DDO operations, so your
// data is intact AND you get a refresh of the list.
Get GetFocusedRowIndex of oDbCJGrid1 to iCurrent
Get phoReportNavigator of oDbCJGrid1 to hoNav
Get ComNavigator of oDbCJGrid1 to vNav
Set pvComObject of honav to vNav
Send ComMoveToRow of hoNav iCurrent False False
End
// Reset record buffer
Move (FindByRowId(INVOICE.File_Number, riOldId)) to bO
Increment iRow
End
Set piRow to iRow
End
End_Procedure // OnTimer
End_Object // oTimer
[code]

Better tuck this one away