Wrong order of parameters: [tt]SET FILTER TO ATC(S4,SUBURB) != 0[/tt]
Simply test ? ATC("a","abc"), ATC("abc","a") and you know even without referring to the help. The names of the parameters cSearchExpression, cExpressionSearched are also not really helping see what is what. You want to search the user input S4 in SUBURB, so S4 is the searchexpression you search in the field SUBURB, SUBURB is the field, which is searched. In general you can also search in an expression. eg field1+field2, so the parameter is named. It's still not very proper naming. I also fall for the order of parameters of such functions very often. A simple test shows simpler than any thought on language and meaning

.
It's not optimal to need a public variable. You can make it a literal expression this way:
Code:
LOCAL lcSearchValue
lcSearchValue="["+CHRTRAN(ALLTRIM(NVL(THIS.VALUE,"")),"[]","")+"]" && For example "[SYDNEY]"
SELECT CUSTVIEW
SET FILTER TO ATC(&lcSearchValue,SUBURB) != 0
LOCATE
The CHRTRAN removes any [ and ] entered by a user. This should never happen, but would break code. Finally the string delimiters [ and ] are used, so ' or " could still be searched. In regard to speed, the final FILTER now will be ATC([SYDNEY],SUBURB) and that is as fast as ATC(S4,SUBURB) without needing a public variable. The substitution is only done once at execution of the SET.
Last not least, I wouldn't put too much into form refresh. I have to maintain code where a typical form refresh contains 100 lines of settings of enabled, readonly, controlsources, etc. The scope of changes of a filter or such settings are typically less global and should be handled more within the controls than the form level, famous example is a navbar, which changes its buttons enabled status based on EOF/BOF in its own usage, not in form.refresh. You can argue also navbar.refresh should reflect any changes of the record pointer done from outside, but don't cramp everything into a form.refresh. Before you start refactoring, first think about where to put what and when to trigger that code by actively calling THISFORM.REFRESH(), even without any code a refresh causes actions and it happens when a form is moved and in some more occasions than you think, when nothing changes needing the code you have there. A filter could also be set on the click of a button. If you're wanting a wow effect, do it in textbox.interactivechange. But then only refresh the grid displaying CUSTVIEW, not the whole form.
Bye, Olaf.