Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

Discussion in 'UI Toolkit' started by bsterling250DI, Mar 27, 2020.

  1. bsterling250DI

    bsterling250DI

    Joined:
    Sep 25, 2014
    Posts:
    78
    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)
     
    a_p_u_r_o likes this.
  2. bsterling250DI

    bsterling250DI

    Joined:
    Sep 25, 2014
    Posts:
    78
    Also i see a "BindingPath" property in the UIBuilder inspector, what use is this and what does it do?
     
  3. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    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.
     
    ninjaram likes this.
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    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.
     
  5. bsterling250DI

    bsterling250DI

    Joined:
    Sep 25, 2014
    Posts:
    78
    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.
     
    uDamian likes this.
  6. genericusername555

    genericusername555

    Joined:
    Sep 17, 2020
    Posts:
    2
    @uDamian - I've just begun to get this working in the Editor. Great feature and thanks for the implementation.
     
  7. marcospgp

    marcospgp

    Joined:
    Jun 11, 2018
    Posts:
    194
    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?
     
  8. calc1fer

    calc1fer

    Joined:
    Oct 5, 2019
    Posts:
    62
    myIntField.Bind(serializedObject);
    myIntField.bindingPath = "m_Health";
     
    AHA1ZINT likes this.
  9. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    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.
     
  10. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    396
    Bind() will traverse the current hierarchy and create bindings objects that will keep field values and their serialized properties in sync. @calc1fer 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.
     
    calc1fer likes this.
  11. marcospgp

    marcospgp

    Joined:
    Jun 11, 2018
    Posts:
    194
    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?
     
  12. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    396
    No, you need to add the children, then call bind afterwards. Bind is a one-time tree traversal operation.
     
    Polygoat and marcospgp like this.
  13. thephoenix007

    thephoenix007

    Joined:
    Nov 29, 2018
    Posts:
    7
    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.
     
    Moyou321, gurth, Mattis and 9 others like this.
  14. BlackclawsK

    BlackclawsK

    Joined:
    Jan 9, 2019
    Posts:
    100
    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:

    Code (CSharp):
    1. public class TestScript : MonoBehaviour {
    2.  
    3. public boolean m_testBool = false;
    4.  
    5. }
    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:

    Code (CSharp):
    1.     // TestScript.cs
    2.     public class TestScript : MonoBehaviour
    3.     {
    4.         public bool m_testBool = false;
    5.  
    6.         private void Update()
    7.         {
    8.             Debug.Log(m_testBool);
    9.         }
    10.     }
    11.    
    12.     // TestScriptEditor.cs
    13.     [CustomEditor(typeof(TestScript))]
    14.     public class TestScriptEditor : UnityEditor.Editor
    15.     {
    16.         public override VisualElement CreateInspectorGUI()
    17.         {
    18.             var gui = new VisualElement();
    19.             var toggle = new Toggle("My test bool");
    20.             toggle.bindingPath = "m_testBool";
    21.             // You don't need the following line in a CustomEditor. You need it if you do it during runtime
    22.             //toggle.Bind(serializedObject);
    23.  
    24.             gui.Add(toggle);
    25.             return gui;
    26.         }
    27.     }
     
    Elapotp and uMathieu like this.
  15. BlackclawsK

    BlackclawsK

    Joined:
    Jan 9, 2019
    Posts:
    100
    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<Type>("NAMEOFELEMENT") and then databind them as needed.
     
  16. LogicFlow

    LogicFlow

    Joined:
    Aug 18, 2018
    Posts:
    33
    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.
     
    Last edited: May 22, 2022
    pandazaurus and rod_lopez like this.
  17. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    187
    does it also work for runtime ui?
     
    ImmanuelScholz, f4bo and bakkoto like this.
  18. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,924
    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)
     
  19. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,924
    (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)
     
    Sluggy likes this.
  20. giresharu

    giresharu

    Joined:
    Oct 11, 2015
    Posts:
    25
    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?
     
  21. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    You can bind to any field that is backed by Serialization, which includes the Editor's fields. If you need to change the data, you can write the final result to a field and bind to that. If you're on 2023.2 (and newer), you can use the new binding system for UI which allows for custom modifiers for your bindings. More here: https://docs.unity3d.com/2023.2/Documentation/Manual/UIE-comparison-binding.html

    Only if the TextField's name is not unique enough. This is why it's recommended to use the BEM pattern for naming elements and classes so you can do a single query: https://getbem.com/naming/
     
  22. azmi_unity

    azmi_unity

    Joined:
    Dec 13, 2020
    Posts:
    62
    This is not the same as view binding that I see when working with Android UI right.

    Would be convenient to have some Attribute that automatically fills up fields of a class with their UXML counterparts. So that I don't have to root.Q finding for each element.