Copy the following into a prg and run it to see what I did. If you type in the age and name box repeatedly before moving the grid or saving then click undo and redo you can decide on the final values you want and save. I am still trying to figure out why my code in beforemove event of grid does not save.
** DEMO OF UNDO/REDO/UNDO ALL
** BY Rob Sutton
** 03/22/06
loForm = Createobject("myForm")
loForm.Show()
Read Events
Define Class myForm As Form
DoCreate = .T.
AutoCenter = .T.
Caption = "Test form"
Width = 500
Height = 300
Add Object lblName As Label With ;
TOP = 35, ;
Left = 60, ;
Width = 100,;
CAPTION = "Name",;
AutoSize = .T., ;
Caption = "Name"
Add Object txtName As myTextBox With ;
TOP = 48, ;
Left = 60, ;
Width = 121,;
ControlSource = "m.First_Name"
Add Object lblAge As Label With ;
Top = 83, ;
Left = 60, ;
Width = 40,;
Caption = "Age",;
AutoSize = .T., ;
Caption = "Age"
Add Object txtAge As myTextBox With ;
TOP = 96, ;
Left = 60, ;
Width = 40, ;
Alignment = 0,;
ControlSource = "m.Age"
Add Object grid1 As myGrid WITH ;
RecordSource = ""
Add Object cmdSave As myCmdSave With ;
TOP = 48, ;
Left = 216, ;
Width = 70,;
Caption = "Save"
Add Object cmdUndo As myCmdUndo With ;
TOP = 48, ;
Left = 336, ;
Width = 70,;
Caption = "Undo"
Add Object cmdRedo As myCmdRedo With ;
TOP = 84, ;
Left = 336, ;
Width = 70,;
Caption = "Redo"
Add Object cmdUndoAll As myCmdUndoAll With ;
TOP = 120, ;
Left = 336, ;
Width = 70,;
Caption = "Undo All"
Add Object cmdExit As myCmdExit With ;
TOP = 240, ;
Left = 336, ;
Width = 70,;
Caption = "Exit"
Procedure Init
Set Deleted On
m.First_Name = ""
m.Age = 0
Thisform.grid1.RecordSource=""
Thisform.cmdRedo.Enabled = .F.
Thisform.cmdUndo.Enabled = .F.
Thisform.cmdUndoAll.Enabled = .F.
Create Cursor Cnames_Undo(First_Name C(50), Age Int, Pointer Int)
Index On Pointer Tag Pointer
Index On Recno() Tag recno_
Set Order To recno_
Create Cursor Cnames (First_Name C(50), Age Int)
Insert Into Cnames Values("Rob",37)
Insert Into Cnames Values("Michelle",23)
Insert Into Cnames Values("Rick",33)
Go Top
Thisform.grid1.RecordSource="Cnames"
Select Cnames
Scatter Memvar
Thisform.Refresh()
Endproc
Procedure Unload
Clear Events
Endproc
Procedure Save_
Select Cnames
Gather Memvar
Create Cursor Cnames_Undo(First_Name C(50), Age Int, Pointer Int)
Index On Pointer Tag Pointer
Set Order To Pointer
Thisform.cmdUndoAll.Enabled =.F.
Thisform.cmdUndo.Enabled =.F.
Thisform.cmdRedo.Enabled=.F.
Thisform.Refresh()
Endproc
Enddefine
Define Class myTextBox As TextBox
Procedure Init
This.AddProperty("llThisChanged",.F.)
Endproc
PROCEDURE GotFocus
KEYBOARD '{CTRL+A}'
ENDPROC
Procedure Valid
If This.llThisChanged = .T.
Select Cnames_Undo
=Seek(1,"Cnames_undo","pointer")
If Recno() = Reccount()
Update Cnames_Undo Set Pointer = 0
m.Pointer = 1
Insert Into Cnames_Undo From Memvar
Thisform.cmdUndo.Enabled=.T.
Thisform.cmdUndoAll.Enabled =.T.
Else
lnRecNo = Recno() + 1
Update Cnames_Undo Set Pointer = 0
Delete From Cnames_Undo Where Recno() = lnRecNo
m.Pointer = 1
Insert Into Cnames_Undo From Memvar
Thisform.cmdUndo.Enabled=.T.
Thisform.cmdUndoAll.Enabled =.T.
Endif
This.llThisChanged = .F.
Endif
Endproc
Procedure InteractiveChange
This.llThisChanged = .T.
Endproc
Enddefine
Define Class myGrid As Grid
Top = 144
Height = 121
Left = 60
Width = 192
ColumnCount = 2
DeleteMark = .F.
RecordMark=.F.
HighlightStyle=2
TabStop=.F.
Procedure AfterRowColChange
Lparameters nColIndex
Select Cnames
Scatter Memvar
Create Cursor Cnames_Undo(First_Name C(50), Age Int, Pointer Int)
Index On Pointer Tag Pointer
Index On Recno() Tag recno_
Set Order To recno_
Thisform.cmdRedo.Enabled = .F.
Thisform.cmdUndo.Enabled = .F.
Thisform.cmdUndoAll.Enabled = .F.
Thisform.Refresh()
Endproc
Procedure BeforeRowColChange
Lparameters nColIndex
Thisform.Save_()
Endproc
Enddefine
Define Class myCmdSave As CommandButton
Name = "cmdSave"
Procedure Click
Thisform.Save_()
Endproc
Enddefine
Define Class myCmdUndo As CommandButton
Procedure Click
Select Cnames_Undo
=Seek(1,"Cnames_undo","pointer")
Do Case
Case Reccount() = 0
This.Enabled=.F.
Thisform.cmdRedo.Enabled=.F.
Case Recno() = 1
Select Cnames
Scatter Memvar
Select Cnames_Undo
This.Enabled = .F.
Thisform.cmdRedo.Enabled=.T.
Case Recno() > 1
Skip -1
lnRecNo = Recno()
Update Cnames_Undo Set Pointer = 0
Update Cnames_Undo Set Pointer = 1 Where Recno() = lnRecNo
Scatter Memvar
Thisform.cmdRedo.Enabled=.T.
Endcase
Thisform.Refresh()
Endproc
Enddefine
Define Class myCmdUndoAll As CommandButton
Procedure Click
Select Cnames_Undo
=Seek(1,"Cnames_undo","pointer")
Do Case
Case Reccount() = 0
This.Enabled=.F.
Thisform.cmdRedo.Enabled=.F.
? 0
Otherwise
Go Top
Select Cnames
Scatter Memvar
Select Cnames_Undo
This.Enabled = .F.
Thisform.cmdUndo.Enabled =.F.
Thisform.cmdRedo.Enabled=.T.
lnRecNo = Recno()
Update Cnames_Undo Set Pointer = 0
Update Cnames_Undo Set Pointer = 1 Where Recno() = lnRecNo
Endcase
Thisform.Refresh()
Endproc
Enddefine
Define Class myCmdRedo As CommandButton
Procedure Click
Select Cnames_Undo
=Seek(1,"Cnames_undo","pointer")
Do Case
Case Reccount() = 0
This.Enabled = .F.
Thisform.cmdUndo.Enabled=.F.
Thisform.cmdUndoAll.Enabled=.F.
Case Recno() = Reccount()
lnRecNo = Recno()
Update Cnames_Undo Set Pointer = 0
Update Cnames_Undo Set Pointer = 1 Where Recno() = lnRecNo
Scatter Memvar
This.Enabled=.F.
Thisform.cmdUndo.Enabled = .T.
Thisform.cmdUndoAll.Enabled=.T.
Case Recno() > 0
Scatter Memvar
Skip +1
lnRecNo = Recno()
Update Cnames_Undo Set Pointer = 0
Update Cnames_Undo Set Pointer = 1 Where Recno() = lnRecNo
Thisform.cmdUndo.Enabled = .T.
Thisform.cmdUndoAll.Enabled=.T.
Endcase
Thisform.Refresh()
Endproc
Enddefine
Define Class myCmdExit As CommandButton
Procedure Click
Thisform.Release()
Endproc
Enddefine
Regards,
Rob