DEFINE CLASS udfobjcollector AS custom *-- Object ref to a container for which object refs are placed into collection array (this.aCollection[]) containerref = "thisform" Name = "udfobjcollector" *-- Array containing all object refs for this.containerref [Object ref to a container]. *-- ie: this.containerref = "thisform" - all thisform objects are in collection DIMENSION acollection[1] *-- Method to fill collection array aCollection with members of all contained objects PROCEDURE fillcollection LPARAMETERS oContainerObject LOCAL ix, nMembers, lnExpand, oObjectRef, aContainerObjects[1] nMembers = amembers(aContainerObjects, oContainerObject,2) FOR ix = 1 to nMembers && Start collecting lnExpand = iif(type("this.aCollection[1]")= "L",0,1) DIMENSION this.acollection[alen(this.aCollection,1)+lnExpand] oObjectRef = eval("oContainerObject."+aContainerObjects[ix]) this.acollection[alen(this.aCollection,1)] = oObjectRef this.fillcollection(oObjectRef) && Recurse ENDFOR * Handle _screen and _vfp to also collect their objects DO case CASE compobj(oContainerObject,_screen) && Handle _screen specially FOR each oForm in _screen.Forms this.fillcollection(oForm) && Recurse ENDFOR CASE compobj(oContainerObject,_vfp) && Handle _vfp specially FOR each oFrmObject in _vfp.Objects this.fillcollection(oFrmObject) && Recurse ENDFOR * _screen.forms # _vfp.objects * So also handle _screen.forms too this.fillcollection(_screen) ENDCASE ENDPROC *-- Execute method for all objects in container with a specific property value PROCEDURE execall LPARAMETERS poContainerObject, pcProperty, pcExpr, pcExecMethodName *!* Sample call for a grid.afterrowcallchange to refresh controls with same recordsource *!* This is handy when there are relation and you don't want the call thisform.refresh *!* thisform.objectcollector1.ExecAll(thisform, ; *!* "controlsource", ; *!* "upper(%_%getvalue%_%) = ["+upper(this.recordsource)+".]", ; *!* "refresh()") *!* Example : Refresh all controls where controlsource = "CUSTOMER" *!* ExecAll(thisform, "controlsource", "upper(%_%getvalue%_%) = [CUSTOMER.]", "refresh()") *!* poContainerObject = thisform *!* pcProperty = "controlsource" *!* pcExpr = "upper(%_%getvalue%_%) = [CUSTOMER.]" *!* pcExecMethodName = "refresh()" *!* Example : Refresh all controls where inlist(controlsource,[CUSTOMER.],[EMPLOYEE.]) *!* ExecAll(thisform, "controlsource", "inlist(upper(%_%getvalue%_%), [CUSTOMER.],[EMPLOYEE.])", "refresh()") *!* poContainerObject = thisform *!* pcProperty = "controlsource" *!* pcExpr = "inlist(upper(%_%getvalue%_%), [CUSTOMER.],[EMPLOYEE.])" *!* pcExecMethodName = "refresh()" *!* Notice how %_%getvalue%_% is used as a placeholder for propertyname in expression this.fillcollection(poContainerObject) && Collect all objects of object IF type("this.aCollection[1]") = "L" && No member objects RETURN ENDIF pcExecMethodName = pcExecMethodName + ; iif(at("(",pcExecMethodName)=0, "()","") && Eval() needs () for EM lcExecMethodName = substr(pcExecMethodName,1,; at("(",pcExecMethodName)-1) && Pure EM name lcExpr = stuff(pcExpr, ; at("%_%getvalue%_%",pcExpr),; len("%_%getvalue%_%"),; "loObjectName."+pcProperty) && Prepare expression FOR each loObjectName in this.acollection && Loop through member objects && Property exists and !protected and object is one we're looking for and EM exists IF pemstatus(loObjectName, pcProperty, 5) ; and !pemstatus(loObjectName, pcProperty, 2) ; and eval(lcExpr) ; and pemstatus(loObjectName, lcExecMethodName, 5) EVAL("loObjectName."+pcExecMethodName) && Execute its own method -pcExecMethodName- ENDIF ENDFOR this.acollection=.f. && Release Object References DIMENSION this.acollection[1] ENDPROC ENDDEFINETo speed up you can move "this.fillcollection(poContainerObject)" to init of custom object and remove lines :