Looking at the dictionary items nothing stood out; they were all multivalued, they all derived their values based upon the code entry. So we decided to go for the sledgehammer to crack a nut approach and added a quickevent to the POSCHANGED event. Column 4 doesn't want to update - we'll tell it to update every single time the user moves cells.
This was sort of successful - but not entirely. Sometimes it worked, sometimes the price column was the only one updated.
In the Sprezz world, "Sort of" doesn't cut it. So just as we were about to start coding a POSCHANGED in the commuter routine to update ALL of the columns we reviewed our options. As is often the way when discussing problems rather than thinking about problems the solution becamse obvious. RTI have optimised the semantic logic layer in such a way that the only symbolics recalculated by default are those that rely on the column that has just changed.
How do they do that?
We can't know the exact mechanism but it's safe to guess that they look at the formula for the symbolic in some way and see if it references the changed column. They doubtless do this once at Window compilation time then cache the results. And what was the formula of the non-updating column?
Because the calculation was reused elsewhere, we'd moved it off into a function - which worked well BUT confused the semantic logic layer as now, as far as it was concerned, the formula was NOT dependent on the code column. The initial solution - as inelegant as it seems, was simply to ensure that the formula contained a reference to the code column so -
et voila now all the symbolics update without any further user intervention.
But that still didn't really satisfy us ̶̶ why should we have to pollute our dictionary items just to make dependencies within the window work? Especially as we have an increasing tendency on new systems to move all symbolic calculations into a control commuter for the table. So we decided to work out how OI was dealing with these dependencies and manipulate them ourselves on the form CREATE event.
The first place to look when trying to establish this sort of information is always the additional features documentation provided by Revelation - or the SYSPROG Inserts as they're more commonly known - OIWIN_EQUATES in this case. Opening this, the area that we're specifically interested in is the equates for the Control Semantics which are associated with the Control Map. Scanning this we come to the rubric "* list of controls to send recalcs to on change" next to column position 14 - CS_RECALC$.
Given that we're dealing with an edit table here, the information is going to be somewhat nested! We could have several data columns which in turn are depended upon by several other symbolics. Describing the structure in English first - column X of controlSemantics@ contains the controlSemantic information for the control we have located at X in the controlMap@.
Value14 of controlSemantics@
controlSemantics@< X, 14, 3, 4, 1> = "ENQUIRIES.EDT_PRODUCTS"
controlSemantics@< X, 14, 3, 4, 2> = "4"
So finally a code sample showing how we achieved the result we wanted without having to change our dictionary columns.
/*
ensure controlSemantics@ is updated to adjust the selling price
when the product code changes. The product code is tn column 2 of
the edit table and the selling price is In column 4
*/
Equ editTable$ To atWindow : ".EDT_PRODUCTS"
Equ sellingPrice$ To editTable$ : @Stm : 4
Equ codeColumn$ To 2
Locate editTable$ In controlMap@ using @Fm setting controlPos Then
dependsInfo = controlSemantics@< controlPos, CS_RECALC$ >
colInfo = dependsInfo<0, 0, codeColumn$>
Locate sellingPrice$ In colInfo using @Tm setting thereAlready Else
colInfo := @Tm : sellingPrice$
dependsInfo<0, 0, codeColumn$> = colInfo
controlSemantics@< controlPos, CS_RECALC$ > = dependsInfo
End
End
This worked perfectly and lent itself to encapsulation in a function to tweak recalculation dependencies as we saw fit.
Nice article. We ran into the very same issue because we manage our calculated column logic in the same way as well. It always looked funny to us to introduce a throw away variable just to satisfy the column dependency logic. ;-) Like you we have our own encapsulation processes but we have not yet resolved whether this should be hard-coded, soft-coded, or handled differently. Trying to manage dependencies away from the calculated column itself requires discipline. How are you tackling this?
ReplyDeleteAs tempting as it was to ask our framework author to work it out for himself at create time by a combination of naming conventions and tab order it seemed more elegant for the programmer to set a custom property on the CREATE event of the window which in turn is interrogated by the POSTCREATE promoted event to set the actual labelled common. This is pretty similar to what we do with our OPTIONCOLS property which we set on the CREATE event to tell the framework which edittable columns should be hyperlinked.
ReplyDelete