if ( ! ( "CCONTROL.VCX" $ set( "classlib" ) ) ) set classlib to ccontrol additive endif if ( ! ( "CCONTROL.FXP" $ set( "procedure" ) ) ) * header class is in ccontrol.prg set procedure to ccontrol additive endif local loHeader, lnX, lcX for i = 1 to tagcount() lcTag = lower( tag(i) ) j = ascan( laControlSource, lcTag ) if ( j > 0 ) with this.Columns[j] * copy object properties because they're not default values or come from dbc lcX = .Header1.Caption .RemoveObject( "Header1" ) .AddObject( "Header1", "hdrSeeker", lcTag ) .Header1.Caption = lcX if ( type( .ControlSource ) == "C" ) .RemoveObject( "Text1" ) .AddObject( "Text1", "txtSeeker" ) with .Text1 .Visible = .t. .mcTag = lcTag .mlUpper = "UPPER" $ upper( sys( 14, i ) ) endwith else .ReadOnly = .t. endif endwith endif endfor * make all col headers left aligned and switch the rest of the headers for each loCol in this.Columns with loCol .Header1.Alignment = 0 if ( .Header1.Class == "Header" ) lcX = .Header1.Caption .RemoveObject( "Header1" ) .AddObject( "Header1", "hdrSeeker", "" ) .Header1.Caption = lcX .Header1.FontBold = .f. endif endwith endforThis grid always builds itself, and I decided to just have the grid look to see if a tag existed at Init() time to know if the column should be sortable. If it is and it's a text field the Text1 is replaced with a txtSeeker class that does the incremental search dirty work.