I already posted a similar question some days ago which I now think misses the core of the problem I was having with UI Toolkit in general.
How do we keep visuals created with UI Toolkit up to date with the underlying data?
This question is answered often and well for the most simple use-case: (e.g.) linking a serialized string
to a Label
. This is enough if I only work with serialized data and even then it’s only enough if I display and edit only the data in its raw state. Something like a Button
that gets enabled or disabled based on serialized data is not possible (I’d like to be proven wrong, though).
But what about data that is not serialized, like e.g. a component received from GetComponent<>()
, or a property that gets changed during runtime (used in inspector). How do we tell our UI to update when those change?
The problem IMO gets more obvious when writing custom inspectors. What is the point of writing one (other than adding simple actions through buttons) if I only can display the data a default inspector already shows? I’m thinking there must be some functionality I’m missing, but the only example I could find of a custom inspector with UI Toolkit shows only how to bind and show serialized fields (which can be achieved with same results without a custom inspector).
This got into a little rant, I’m sorry.
I hope I could get my problem across and that there is a solution, or that I’m just missing something obvious.
Thanks for your attention.
Right now, the best way would be to check the value during the update phase, and you will have to write your own logic for that.
It is technically doable, but is not the most meaningful work and increase the maintenance efforts to change the UI, or the code when you have a lot of data to update.
What you are suggesting is that we do some boilerplate code that would connect ANY VisualElement’s property to ANY object field in your game, into a code that we cannot know in advance. It would have to use magic to work (aka reflection), and even then, reflection tend to be slow, so we would have to do something to make it fast. Also, a lot of error are possible if the reflection part is not strongly typed.
The good news is that this is exactly what we are working on 
If you look at the UI Roadmap (https://unity.com/roadmap/unity-platform/gameplay-ui-design select “UI Design”), you’ll notice we are currently working on data binding.
This will unlock a workflow where you will be able to associate data properties, that can be strongly typed, within your UXML document. We are also looking at supporting event bindings this way.
It does take some time to make the full system, including the builder, to work with this new concept, so I won’t commit to a timeline for this release.
1 Like
You had me there for a second!
But to hear that my problem was valid and is being worked on is the best answer I could have hoped for. Thank you, this is very much appreciated!
You mean using EditorApplication.update
?
For later reference: Another workaround I have in mind is wrapping the parts that need to be up to date in an IMGUIContainer
, resorting to IMGUI only for those parts (if you only need the data in a certain section).
But thanks again for your swift response!
I thought you were targeting a runtime application. For the editor, the best would currently be to use the serialized object’s bindings. The new binding system will also work in this context, but it is much more needed for runtime as we don’t have the serialization there!
Even if you are using an imgui container, the ui refresh still need to be triggered. AFAIK this is automatic when you change a value on a ui element. Changing the value can simply be done in the EditorApplication.update calls. Another way of doing this is possible if you can have as subscriber on your class that would be triggered by a setter. I think you would need to change the value with this callback.
In the game view, I know we check if something has changed at every frame, but for the editor we are more efficient, frames are only happening if there is a change.
I realize this is something we are not covering in our migration guide:
I may have missed something, don’t hesitate to ask any other question and share more details if it does not go according to plan!
Imgui container are a good backup, but they do kill the performance when rendering a lot of elements.
I don’t think I get what you mean. Using serialized bindings, for me, means settings the binding path, which means that I can only get/set the raw data.
Could you link to, or maybe even provide, an example how I could achieve such a behavior?
// Might be target of custom inspector, or any other GameObject
GameObject go;
// This should be called anytime GameObject changes
button.SetEnabled(go.GetComponent<MyBehaviour>() == null);
Or this case:
// Might be target of custom inspector, or any other GameObject
SerializedProperty prop;
// This should be called anytime prop's value is updated
button.SetEnabled(prop.objectReferenceValue == null);
Or any other case that goes beyond just providing a field for that serialized data.
This would already be a suitable workaround, if it refreshes automatically.
Thank you for your time!
1 Like