I have a model element with two properties: a ListProperty (containing "wrapped" ReferenceValues) and a String ValueProperty. The value of the second property is derived from the content of the first (it simply concatenates the IDs of all the referenced elements). The properties are as below:
@Type(base = FusibleRef.class)
ListProperty PROP_INPUTS = new ListProperty(TYPE, "inputs");
//ValueProperty that I want to refresh based on the above ListProperty
ValueProperty PROP_FEED = new ValueProperty(TYPE, "Feed");
However, my implementation of DerivedValueService is having its compute() method called only once, when the file is opened in the Sapphire editor, and nothing is happening when I make any changes to the "inputs" property. What might I be doing wrong?
The issue is with your @DependsOn. As specified, it only catches changes to the list itself (adding an element, removing an element, re-arranging elements). It doesn't catch changes to internal properties of the contained elements. You want something like this instead...
Never mind. The @DependsOn annotation causes a property refresh, which will call DerivedValueService.value(), which will not cause the value to be re-computed. The @DependsOn annotation is really a blunt legacy system for wiring up dependencies. The proper way to get DerivedValueService to update is for the service itself to listen on its inputs (override initDerivedValueService() and dispose() to do this). When your listener detects a change, call refresh() method in the service, which will call compute() and broadcast a change if the value changes.
Konstantin-- Thank you. Overriding the other methods did the trick.
This is a related question (and should probably go in another thread), but...if I want to wait on retrieving a referenced element (out of my list property) until the user has had a chance to actually browse for and select one, is there 1) a particular PropertyEvent type to use; 2) an alternative to listening on each individual element in the list?
I am not quite sure I understand your question, but I can answer this part:
> an alternative to listening on each individual element in the list
When you attach a listener, you can use a model path. For instance, using a path like "Inputs/SomeValueProperty" will ensure that you are listening on all current instances of SomeValueProperty as well as all future ones. Sapphire will ensure the listener is propagated to the new elements when list changes.
You will likely want to focus on PropertyContentEvent. See FilteredListener for an easy way to do that. At the very least, you will want to ignore PropertyInitializationEvent.