Can someone explain "Binding" to me in the context of UI Toolkit?

Hello,

In my experience “Binding” is a term used to form a relationship between class types, i.e. Binding an Interface to a class for the purposes of dependency injection.

I see the term Bind being used a lot throughout the demo as well as throughout this forum, but the concept is foreign to me. From looking at the demo, “Bind” just means to initialize the values in the different elements, but it seems like a one time thing, where as Bind to me implies some sort of persistent behavior that if the data changes those properties will automatically detect the changes and update. Maybe that’s true, but it’d be great if someone could illuminate me (pretend I know nothing about UI other han working with uGUI as I have for the last 5 years)

2 Likes

Also i see a “BindingPath” property in the UIBuilder inspector, what use is this and what does it do?

Bind, in the context of UI Toolkit, does in fact mean a persistent link between UI and data. Instead of manually registering for ChangeEvents and manually polling your data for changes, when you Bind() your UI controls to an Object, we do this for you. We keep the data updated from user changes to the UI field, and we keep the UI field current with the data if the data is changed elsewhere.

If you have a medium amount of minutes to spare, this video goes through the different pieces of the UI Toolkit C# API, USS, UXML, Events, and finally, how Bindings tie all these together and help you simplify your UI code.

2 Likes

If you were to Bind() an IntegerField to a Unity Object (like a MonoBehaviour) that has a field named m_MyInteger, you could give this IntegerField the “BindingPath” of “m_MyInteger” and it will be kept in sync with the value of your “m_MyInteger” field on the object.

Ahh, i see, it sounds an awful lot like ReactiveExtensions which i’m quite familiar with. I was wondering if you had a complex object with multiple properties how it might select the property and it sounds like BindingPath is just that.

I’ll play around with these some more, and thanks for sharing that presentation, i’ve only seen the unite demo before now.

1 Like

@uDamian - I’ve just begun to get this working in the Editor. Great feature and thanks for the implementation.

At what point should Bind() be called? If I call it on a root element and then add child elements to it, will the bindings on the children work?

myIntField.Bind(serializedObject);
myIntField.bindingPath = “m_Health”;

2 Likes

I think it would work only if the “root element” wasn’t added to a panel yet, because bindings in the editor are applied elements are added to a window. If your root element is already part of a panel, I’m pretty sure elements added after its bound won’t receive the binding themselves.

I’d say it’s better to call Bind on an element after all its intended children are added; it works every time. Also, if you’re returning a root element from a PropertyDrawer or a custom editor, you don’t need to bind it; Unity binds it for you.

Bind() will traverse the current hierarchy and create bindings objects that will keep field values and their serialized properties in sync. @CQTD For this to work properly, you need to set the bindingPath first, then call Bind once on a common ancestor. Changing the bindingPath afterwards will require you to call Bind() again.
As @oscarAbraham mentionned, on a custom inspector, you only need to set the bindingPaths, the editor will call Bind for you.

1 Like

To be clear, If I call Bind() on a root element and then add child elements to it, will the bindings on the children work?

No, you need to add the children, then call bind afterwards. Bind is a one-time tree traversal operation.

2 Likes

Is there ANY way you can update your documentation to reflect this type of implementation? I’m trying to figure out how to do this, and it all sounds great in theory, but there are 0 examples out there. The video posted doesn’t express the implementation with databinding without writing 100 lines of code, and seems to over-complicate binding data to elements, it also focuses on the unity editor, which a lot of people don’t care about.

I’m really frustrated with this system as all of your documentation talks about using this with the editor, and then a splash of “Oh yeah you can build your game UI with this too” and that’s it. Its been non-stop trial and error for me, and I’m almost ready to give up and go back to the old clunky UI. At least I can go Label.text = “Text” without having to jump through 20 hoops or figure out your complex system.

I’m sure its not as complicated as in my head, but there’s minimal tutorials out there by other people, and whomever wrote the docs on this didn’t do that great of a job, otherwise people wouldn’t be here asking about what should arguably be the easiest thing to do with any UI. I’m tired of making very little progress on my game because I’m beating my head against a system that on the surface is easy to use, but has so many caveats that its almost not worth it.

It appears that this should be treated like WPF data bindings, but knowing unity its not that easy. And if it is, whomever wrote your documentation is REALLY bad at explaining that. There’s no context in your documentation on data binding - Ex. .bindPath = “m_name” ← what is “m_name” ? I did ctrl-f on the entire page and that did not come up but twice, neither one providing any context as to what that string is supposed to represent or come from, do I randomly put a property name there and hope that the unity gods are able to find it in all my monobehaviors? Sorry to rant, I’m really frustrated at the lack of reasonable documentation on this, and the one video you guys posted I watched in its entirety, and all it did was tell me that to update a UI - Object relation I gotta write 30 lines of code, as opposed to a simple Mylabel.text = “This is easier than writing a handler to watch the object”

Maybe that IS the way to do it, if it is, you’ve overcomplicated something that should be super easy to do. Hell WPF has been out for a decade and its got data binding down. I’m also not sure why you just didn’t go with something like Razor cshtml, Bind a model to the view and allow code blocks within the HTML. Either way, Imma go back to the old unity UI system until you guys fix your bad documentation on it. If you intend people to use this to build game UI’s stop writing documentation only on editor UI’s which, to be completely honest, isn’t as big of a deal… you don’t hear people complain about unity’s editor UI tools, you hear them complain about building game UI’s in it.

14 Likes

To really quickly get started with databinding just do the following. Create a script that has serializable properties of a base type. Note the name of your serialized property (or field). Concrete Example:

public class TestScript : MonoBehaviour {

public boolean m_testBool = false;

}

In this case you’d write down m_testBool.

Then create your UI. Create a control that matches some serialized property (or field) of your script. (For example a Toggle for a boolean, or a TextField for a string).

Set the bindable path of your control to the name of your property (or field). So in this case the bindable path would be m_testBool.

Then explicitly bind your object to the control. Complete Example:

    // TestScript.cs
    public class TestScript : MonoBehaviour
    {
        public bool m_testBool = false;

        private void Update()
        {
            Debug.Log(m_testBool);
        }
    }
   
    // TestScriptEditor.cs
    [CustomEditor(typeof(TestScript))]
    public class TestScriptEditor : UnityEditor.Editor
    {
        public override VisualElement CreateInspectorGUI()
        {
            var gui = new VisualElement();
            var toggle = new Toggle("My test bool");
            toggle.bindingPath = "m_testBool";
            // You don't need the following line in a CustomEditor. You need it if you do it during runtime
            //toggle.Bind(serializedObject);

            gui.Add(toggle);
            return gui;
        }
    }
3 Likes

For runtime UI its really quite similar. You just have to get a reference to the visualelement first. You can get that from the UIDocument that has loaded the uxml. Then just databind as appropriate in there.

You can get individual elements from the uxml by querying for them: visualElement.Q(“NAMEOFELEMENT”) and then databind them as needed.

Seems it’s not as simple as you suggest. .Bind() and .Unbind() are not available except for Editor bindings. The .binding property is available on VisualElement (BindableElement), but doesn’t seem applicable for binding e.g. a GameObject or ScriptableObject - which is what you’d typically do at runtime.

Is binding in this manner even possible at this stage, for runtime UI? EDIT: The answer is not just yet .

2 Likes

does it also work for runtime ui?

3 Likes

I think half the problem is that this doesn’t generally work. It works in some versions of Unity, some of the time - most of the time if you’re lucky.

In 2019.4.LTS it failed often - especailly for the Toggle example! - and in 2022 it was broken fairly recently.

If Unity properly documented the whole binding system - which I have still never seen an actual description of - I think that three things would happen:

  1. A lot of bugs in UIToolkit would become immmediately obvious (over the last 5 years I’ve noticed that many of the showstopper UIToolkit bugs we run into on multiple projects are hiding behind the massively over-complicated and under-documented Binding system) - and the UIToolkit team could quickly fix more of them.
  2. End-users would stop running into the same painpoints over and over again: data getting out of synch, undo not working, UI not updating, data not serializing, editor not persisting, etc
  3. Usage of UIToolkit would increase significantly: most of the people I know who sitll refuse to use UIToolkit are mostly doing so because of the bugs in Binding / inability to fix any of their own code that is Bidning-related because of the lack of docs from Unity.

TL;DR: Unity has consistently pretended that Unity’s version of Binding is in some way ‘normal’, or ‘simple’, or ‘standard’. This is absolutely not true: Bindign in other langauges/frameworks/engines is (or can be) all those things, but Unity is none of them. Mostly because Unity’s Binding has to work with all of Unity - especially: Unity Serialization, which itself has many obscure but critical details - and those details are critically important when you’re dealing with data.

(or in other words: I found this thread today because I am yet again debugging a data-loss bug caused by UIToolkit actively preventing the UnityEditor from saving a scene. Very frustrating. In this case: I’m pretty sure it’s a bug in UIToolkit that has already been fixed, and only old editros are affected - but there is no way for me to check that becuase no-one outside Unity knows how Binding is even supposed to work)

(to be clear: most of the above is in my opinion a side-effect of having to support/work with the existing core UnityEngine, and the problems that brings. e.g. anything that has to interact with Unity Serialization - and for UI: SerializaedObject etc which is an API that was never finished being written - is a nightmare. Unity’s support for Generics is still incomplete. Unity’s support for C# interfaces is still incomplete. All these make it extra difficult to get this right)

1 Like

If I have a TextField in my editor, but I don’t want to directly assign it to a type in MonoBehaviour, but rather process it internally in the editor first, turning it into other data before passing it to MonoBehaviour, does that mean I can’t use Bind? Or can I bind to the fields of the Editor class? Do I have to write such complex hard code like string text = root.Q("AddressPreviewer").Q("SlotHashesEnd").Q<TextField>("Address").text; to get the value of TextField?