Register callback for after a bound property has been updated

I have a situation that is proving somewhat tricky, and I’m wondering if I’m missing some relatively easy way to handle this.

There is a particular ScriptableObject subclass for which we have a custom inspector. In addition, there is a custom window that has an InspectorElement which shows said custom inspector for a particular ScriptableObject (and that custom window also has other things that are useful to see/manipulate at the same time).

The custom inspector has fields (EnumFields, etc.) bound using the Binding Path that can be specified in the UI Builder. When one of these fields changes, the value in the underlying ScriptableObject changes. In isolation there are no problems there.

Where I’m running into an issue is in the custom window with the inspector element. I want the ability to receive some sort of a callback when one of the fields of the ScriptableObject has changed, so then I can update other things in the window that are not part of the ScriptableObject’s inspector. The issue that I’m having is, if I use RegisterCallback() with a ChangeEvent for any given field, the window’s callback is getting called before the binding for that field. In other words, the ScriptableObject has not yet been updated when the window’s ChangeEvent callback is called.

I could take the newValue in the ChangeEvent parameter, but that means splitting the window update into several different pieces that update independently depending on exactly what changed. I already have a method that takes an object of the ScriptableObject’s type and refreshes the whole window accordingly, so I’d really like to make use of that. But the order of operations is proving difficult.

Is there a way to register for a callback that says “This bound value has changed (and is now updated to the new value)”? Or, even better, is there a callback for when a ScriptableObject has been changed, so I can refresh the window once that has happened?

[quote=RobO_HB, post: 9194735, member: 409058]
I could take the newValue in the ChangeEvent parameter
[/quote]
Not sure I followed 100% but could you not update the SO with the value from the parameter manually and then trigger the redraw? So no matter which comes first the SO is always up-to-date. The window would be redrawn twice, but the second time it would be coming from the registered change event with all data set accordingly. Bit of a waste but maybe a workaround.

Granted that you modify your value in a setter then just invoke an event (regular or UnityEvent) from there and any script that is listening will be notified.

Change event seems to provide an old and new value: Unity - Scripting API: ChangeEvent<T0>

So you probably need to broadcast this information as well between the custom inspector and the editor window.

Hi. I’m not sure I understand completely your case. If you share some code and images, I may be able to offer some ideas that could solve your problems better. That said, there’s certainly ways to do exactly what you are asking at the end of your post:

Yes! Use the TrackPropertyValue extension method.

Yes! Use the TrackSerializedObjectValue extension method. I haven’t tested it with the most recent Unity versions, but, at least in the past, it had some problems with SerializeReference fields, especially when those fields created circular references. Just be aware of that.

I’d suggest using these extension methods with an element that’s replaced every time you change which ScriptableObject is being inspected in your Window, as the only way to stop tracking a property or an object is to remove the VisualElement that’s tracking them.