How to keep a UI element synced with a C# variable

Hello!

I’ve been getting into UI Toolkit and to be honest the documentation at this stage is a little abysmal - the developer guide says a lot about how things work internally but now how to actually use them.

The separation between UnityEditor.UIElements and UnityEngine.UIElements is also unclear.

The Unite Copenhagen 2019 talk has a great overview of the UI Builder (which is an awesome tool) but the way the UI interacts with the game is never touched upon.

To sum it up, I couldn’t find any tutorials or code examples on how to update a runtime UI so it stays synchronized with game values (such as health bars, score counts, etc.).

The scripting API is not very user friendly (and maybe is not intended to be at this point) so I couldn’t use it to learn much about this. I saw there are interfaces for bindable visual elements and binding methods but I am not sure how it works or whether it is preferable to manually set the values themselves each frame.

There is a bindings page on the manual but at least for me it is hard to understand. I could be mistaken but I also don’t think there is a runtime UI example, only code for in-editor UIs.

I only recently discovered the in-editor samples (Window > UI Toolkit > Samples) and those might be the most valuable thing I found so far, in terms of practical digestible examples of basic functionality:

The problem is that some things are still unclear, such as where the container variable comes from and what is its type in the C# code above.

So here are the questions I have:

  • How can I update UI values from my code?
  • Is there more than one way to do it? (such as binding vs manually setting the values each frame)
  • Is there some part of the documentation I’m missing that I could learn from?

And here’s an extra suggestion: open source your documentation on Github so users can submit pull requests. I would have already submitted a few for some pages of the manual which are unrelated to this post.

Thanks for all your work on UI Toolkit guys!

1 Like

I finger out it by toggle example.
that is cool like html

1 Like

I’ve been binding values from UI controls to c# using value changed events.

container.Query<Slider>("name").ForEach(slider =>
{
    slider.RegisterValueChangedCallback(delegate(ChangeEvent<float> evt)
    {
        theValueThatShouldBeChanged = evt.newValue;
    });
});

If you’re using the UIDocument script to get your UI visible, your “container” could for example be

public UIDocument rootUIDocument;

...

// The root visual element of your UI document. You could query this
rootUIDocument.rootVisualElement;

// Or you could define a name for the container of your UI control and only query inside that to find the relevant control
var container = rootUIDocument.rootvisualElement.Query<VisualElement>("ui-element-container-name");

I’m not sure if there’s really even a good way to do it the other way around. Maybe you just have to manually use UQuery to find the relevant control and change the value that way. I’m not even sure if unity’s binding works in runtime UI? The documentation seems sort of scattered and confusing on the subject.

1 Like

All fields have a value property that you simply assign to, ie:myToggle.value = true;. This can be done from the Update() method

To apply the changes from the ui back on your data:
myToggle.RegisterValueChangeCallback((evt) => myData.theFlag = evt.newValue);

Bindings are only available in the editor using SerializedObject/Properties for now. We intend to provide a runtime value binding solution in the future

After installing the package to get runtime support, in the PackageManager window, select the com.unity.ui package and then install the Samples in your project. some examples might be useful,

Thanks for the feedback! I’ll forward this suggestion to the doc team

2 Likes

Thank you for your reply!

I couldn’t find that property in order to update a label, are you sure that property is always the one that should be changed?

Forgive me for the noob question, but is there a particular reason why serialized objects only work in editor scripts?

Thank you!

Something I still don’t understand from my original post is the difference between the UnityEngine.UIElements and the UnityEditor.UIElements namespace. Don’t in-editor UIs have to use things from the UnityEngine namespace?

You’re right. Label implements the INotifyValueChange interface, but in a non-explicit way. You can set its string with both label.text or ((INotifyValueChanged)label).value, use whichever seems the easiest to you :slight_smile:

UnityEngine.* namespaces means you can use this both in the runtime and the editor
UnityEditor.* stuff is editor-only

SerializedObject and Properties are an editor-only feature.

1 Like