Thought I’d share a technique I’ve started using, enabled by objectScript() in v7.7, and possible with runScript() in v7.8. Specifically, how to create an “output” parameter in a template that instances can bind to? Publicly visible template parameters cannot be the destination of a binding inside the template. The solution so far is to create a template parameter and an internal property for each output, bind the appropriate tags/expressions to the internal property, and use the template’s ‘propertyChange()’ event to copy from the internal property to the template parameter.
With the help of objectScript() or the new runScript(), a more direct solution is possible: wrap the binding to the internal property in a function call that will also write to the template parameter. I use the following function in shared.util to handle gui thread property assignments:def assignLater(comp, prop, val, ms = 0):
import system
def assignLaterInvoked(c=comp, p=prop, v=val):
try:
setattr(c, p, v)
except:
c.setPropertyValue(p, v)
system.util.invokeLater(assignLaterInvoked, ms)
return val
Note the return val at the end – it allows this function to work in a binding while also sending the value elsewhere. An example: given template parameters ‘tagfolder’ & ‘output’, this expression binding on an internal property will keep ‘output’ up to date:objectScript("shared.util.assignLater(binding.target, 'output', args[0])",
tag("[default]"+{myTemplate.tagfolder}+'/tagname'))
I haven’t tested the new runScript() features in Ignition v7.8 yet, but it would be something like this:runScript("shared.util.assignLater(self, 'output', args[0])", 0,
tag("[default]"+{myTemplate.tagfolder}+'/tagname'))
Two big advantages here: (1) the assignment code stays with the binding & (2) it runs all the time like any other binding.
The utility function could be simplified if you never need the delay – bindings always run on the gui thread (so far). Anyways, hope this helps someone.