Ok....
Clive is right, it is do with the focus wanting to go the other grid and the current grid wanting to keep it.
This would generally happen during a save, due to a validation error or clicking no on the verify save dialog, in both cases the current grid wants to keep the focus.
However as the other grid is trying to take the focus and it's an activeX control, we need to exit the current grid and allow the other grid to take the focus, else all focus hell breaks out.
But I think I have a solution, does need more testing, so please give it a go and let me know how it works.
In the attached test view, I have an order header grid (parent) and a order details grid (child).
In the child grid I use the ShouldCommitOnObjectExit to check what object we're leaving to, if it's the order header grid i'll defer the save and allow the exit. If it's a normal dataflex control then just do the normal behaviour.
The save is then processed in OnIdle after the focus has been handled.
Also if we clicked on another row in the order header grid we don't want the row to move, so we'll stop the row changing if there's still change in order detail DDO (must be doing a save), we'll also record the old and new row numbers. These are used in the OnIdle during the actual save to show the correct row beforehand and move the focus to right object afterwards.
Code below, and test view based on the sacred Order Entry example attached.
Parent Grid
Code:
Property Integer piOld_Row -1
Property Integer piNew_Row -1
// RowChanging:
// Augmented to cancel the row change as the order details grid is deferring the save as it's changed and
// we're not ignoring the changed state so we want to stay on the current row, it's ignored when the save
// actually happens
//
Function RowChanging Integer iOld Integer iNew Returns Boolean
Boolean bCancel
If (pbDeferred_Save(oOrderDetail_Grid)) Begin
Move True to bCancel
Set piOld_Row to iOld
Set piNew_Row to iNew
End
Else Forward Get RowChanging iOld iNew To bCancel
Function_Return bCancel
End_Function
Child Grid
Code:
Property Boolean pbDeferred_Save False
// ShouldCommitOnObjectExit:
// If we're exiting to the order header grid and we need to save, we need to defer it and allow
// and the order header grid to take the focus, else you end up in a focus mess
//
Function ShouldCommitOnObjectExit Handle ohDestination Returns Boolean
Boolean bRetval
If (Changed_State(oOrderDetail_DD) and ohDestination = oOrderHeader_Grid(Self)) Begin
Move (False) To bRetval
Set pbDeferred_Save To True
End
Else Forward Get ShouldCommitOnObjectExit ohDestination to bRetval
Function_Return bRetval
End_Function
// OnIdle:
// Augmented to handle the deferred save after the suppliers grid has taken the
// focus
//
Procedure OnIdle
Boolean bCancel
Forward Send OnIdle
If (pbDeferred_Save(Self)) Begin
Set pbDeferred_Save To False
// Move to the back to the old, visually the row had moved to the new
// row so we'll put it back so it all looks correct on the screen
Send MoveToRow of oOrderHeader_Grid (piOld_Row(oOrderHeader_Grid))
// Save the row and handle the focus accordingly based on the result
Get CommitSelectedRow To bCancel
If (NOT(bCancel)) Begin
Send Activate of oOrderHeader_Grid
Send MoveToRow of oOrderHeader_Grid (piNew_Row(oOrderHeader_Grid))
End
Else Send Activate
End
End_Procedure