If you are using VFP 9, you can use BindEvent() like this in the grid's Init():
FOR EACH loColumn IN This.Columns
FOR EACH loControl IN loColumn.Controls
*** Now make sure we call te sortgrid method when we click on a header
IF LOWER( loControl.BaseClass ) = 'header'
BINDEVENT( loControl, 'Click', This, 'SortGrid' )
ENDIF
ENDIF
ENDFOR
ENDFOR
Then, in the SortGrid() method, you can figure out which header was clicked and take appropriate action like so:
*** First of all, see which column fired off this event
AEVENTS( laEvents, 0 )
loHeader = laEvents[ 1 ]
IF VARTYPE( loHeader ) = 'O'
*** First See if a ControlsSource was set for the column
WITH loHeader.Parent
lcField = ''
IF NOT EMPTY( .ControlSource )
*** Cool. Use it to decide how to sort the grid
IF NOT EMPTY( .ControlSource ) AND ( '.' $ .ControlSource ) AND NOT( '(' $ .ControlSource )
lcField = JUSTEXT( .ControlSource )
ENDIF
ENDIF
ENDWITH
ENDIF
You can use code like this to do the actual sorting:
LOCAL llAllowCellSelection, lcFrom, lnBuffering
*** There seems to be a refresh issue here
*** because even though the data is in the cursor
*** it is not showing up in the grid after the sort
*** and it looks like it is related to AllowCellSelection being .F.
llAllowCellSelection = This.AllowCellSelection
This.AllowCellSelection = .F.
This.Refresh()
KEYBOARD '{CTRL+TAB}'
lcFrom = This.RecordSource + [ ORDER BY ] + This.cSortField + [ ] + This.cSortOrder + [ INTO CURSOR qTmp NOFILTER]
SELECT * FROM &lcFrom
SELECT ( This.RecordSource )
lnBuffering = CURSORGETPROP( "Buffering" )
IF lnBuffering > 3
*** Since we are in view mode, the grid's RecordSource should have
*** no pending changes, but if it does, they are spurious and
*** we can throw them away
TABLEUPDATE( 1, .F., This.RecordSource )
CURSORSETPROP( "Buffering", 3, This.RecordSource )
ENDIF
ZAP
APPEND FROM DBF( 'qTmp' )
GO TOP IN ( This.RecordSource )
CURSORSETPROP( "Buffering", lnBuffering, This.RecordSource )
USE IN qTmp
This.AllowCellSelection = llAllowCellSelection
This.Refresh()
This.SetFocus()