Mini-tutorial: Data binding with UI Builder and C# in 5 minutes

Hi. I’m Eduardo from the Tech CMM team at Unity. In this short post, I would like to share some quick tips we discovered while creating our longer format e-books and YouTube tutorials. I hope they can come in handy to many of you.

With data binding, now available in UI Toolkit in Unity 6, your game interfaces can automatically be updated when a property value changes, and vice versa. Previously you had to complete this task via a UI manager and an event system to keep track of those changes. But this doesn’t need to be the case with data binding. Bind Visual Element (or custom controls) properties in UI Builder, from attributes and styling properties, to a variable in your code or ScriptableObjects, and you are set!

There are many ways to set up bindings, as you can see in the documentation. In this post, I focus on setting up bindings in UI Builder and the data source from C# and examples that work for runtime and Editor tools.

To get the most from this post you should have prior knowledge of how to use UI Toolkit and UI Builder. To follow along, you can get this small sample project for Unity 6.

Essentials to get it working: Data source and data source path

Data source is the object that contains the properties you want to bind to. Visual elements will inherit the data source from elements higher in the Hierarchy unless they override it. You only need to set a data source to a parent element once.

There are two common ways to add the data source:

  • From UI Builder: Add a ScriptableObject containing the data
  • From C#: Assign a data source (which can be a common type or any C# object) to the desired visual element, typically the parent or root.


Two ways to add a data source in UI Toolkit

The data source path is the path from the data source to the property to bind to an element’s property. To add a binding from UI Builder, find the property you want to bind, click on the three dots and select Add binding…


The Add binding window and its settings

The Add binding window provides the following settings:

  • Property (or BindingId): This is useful to check if you want to set bindings from code, where the BindingId might be required. We won’t use it for now as we are using UI Builder.
  • Type: Make sure the property type in your data source path matches the type needed for the property binding; if this isn’t the case you can create a converter for it.
  • Data source path: This is the path to the property to bind.
  • Binding Mode: A powerful feature of data binding; you can either display values from the source (the default behavior in UI Builder, To target) or also modify the values with the input from the UI (Two Way): For example, if a player wants to change their player name, you’ll want the changes to be reflected in the variable in the code, so the info is used in the game.

Once it’s done, one of two purple icons will appear next to the property in UI Builder. An icon outlined in purple means the path could not be resolved at this time (it’s missing the data source or a converter to provide the right type for example). A solid purple icon means that the binding has been resolved (the data source, as a ScriptableObject, has been set or the binding type might not require a data source).

If we successfully connect both we can see how the UI in the game displays the bound properties. If you are making an Editor tool, the set up is identical for binding properties.

:light_bulb: Tip: You can find the available properties to bind from a data source class by assigning said class in the Data Source Type field. If you use a ScriptableObject you can directly select the variable from the list, but in many cases the data source will be changing and living in a Monobehaviour.

Displaying a custom class or struct

Let’s use a simplified example of a custom item in a game: A shop item that has color and float properties. A convenient way to display those items in your UI could be to create a visual element for the class or struct variable of the item with a child visual element per variable of the class to display.

The parent element could have the data source path pointing to the variable, and then the child elements directly bind to the variables inside the class or struct. You can set it up from UI Builder in a similar way to the animated image.

:light_bulb: Tip: For elements that you plan to instantiate many times, like shop items, you can convert the parent visual element into a template to reuse many times. When you convert a visual element into a template by right-clicking and selecting Create Template, the bindings remain there. Therefore, if you instantiate this template many times but assign a different data source path to the parent of the same type, the child elements will display the corresponding values accordingly. I follow this method in the following examples.

Lists displayed with ListView

A common use case will be to create many items on the fly from code at runtime. To handle large numbers of items the ListView element includes functionality to auto propagate the list with items from a list type. The ListView will instantiate child elements using a template. You can see the configuration in the UI Builder image below. From here we must set up these properties.

  • The Data Source property should point to the list type of variable to use for the binding, the one containing all the items in the list. You assign this from C#.
  • Set the Binding Source Selection Mode to Auto-Assign so the list will be auto populated based on the source property list
  • Choose the Item Template for the child elements in the list. As previously mentioned, a template can already have bindings. They will be binded to the corresponding item in the list when instantiated.

An important step here is that you need to make sure the BindingId (itemsSource) is set up for the ListView – as it’s not available in the UI Builder interface, you need to do it in C# like (see the code snippet below), or also add the binding directly in the UXML file. In C# data source paths are strings in a Property Path.

Remember to add using Unity.Properties; at the top of the script.

To test it, you can populate the list from the Inspector and see how the list in the UI responds to changes at runtime. The list is using a template like the one previously created to display the values from the struct Item, where a Color value is used for the background color of the Visual Element and another FloatField to display the float number.

Arrays displayed with ScrollView

Another common use case could be the need for instantiating elements from an array, and adding those as elements inside another visual element or ScrollView while keeping them binded to their source in their array position, for example, in an inventory or objectives menu.

Open UI Builder and add a ScrollView; the data source path for it will be the array containing the items that we want to add. You can add it here. Just for a change I’m making the scrolling horizontal, which could work well for a level objectives menu, for example.

In your monobehaviour script make a public variable for the VisualTreeAsset which is the template UXML file that we created before for an item.

The array ArrayScrollView is part of the data source, which uses myData, our custom class used for our game data in the previous examples.

From code, I’ll add child elements to the ScrollView based on the template.
The binding will be done by once again assigning a data source path which in essence is just positions in the array, [0], [1], [2] and so on. The template element connected to the array position has the child elements displaying the item values itemColor and itemFloat.

This is the simple code assigning the data source path to each instance of the template.

The result should look something like this, with the values that I populated in the Inspector. You can use the same process to bind any visual element to a value in an array.

Any other examples missing?

Reply to this thread if you want to see another use case example for data binding. You’ll also find data binding know-how in these recent videos:

The e-book User interface design and implementation in Unity is an excellent guide for new and experienced Unity creators who want to learn about the foundational concepts and workflows of UI Toolkit.

Finally, don’t forget to check out the UI toolkit samples here.

17 Likes

Thanks for the tips!

Are there plans to embed, link, or move these tips in the official documentation? Our current project does not use UI Toolkit, but I anticipate the next one will. So I’d love to be able to read this again when I’m in the thick of it, and I fear I’ll have trouble finding this forum post again. Sure I can bookmark the post, but I feel this is not the appropriate way to find learning material.

4 Likes

Hi. The documentation has the most comprehensive info possible on the topic, with links to other samples, etc. I will however check with the team about about adding this one to the doc links. Like we do for our tech e-books, videos or samples we base our content on the documentation available and put it to practice illustrating the process. I hope this one will help in your UI toolkit project.

1 Like

wrong thread I think

Also, How to bind data from a class which is not ScriptableObject. say from Monobehaviour class

Also, How to bind data from a class which is not ScriptableObject. say from Monobehaviour class

In terms of declaring bindings, it’s exactly the same way between a ScriptableObject and an arbitrary C# type. The difference is that the dataSource needs to be set through code, because the UXML format only allows to reference assets.

Got it. Can you direct me to the page where I can find more information about this! Or share a code snippet if possible, how to set up the binding at runtime for from C# objects.

You can take a look at this page, where there are some snippets.

In a nutshell, to set up a dataSource on an element, you would assign the VisualElement.dataSource property, which takes an arbitrary object. If you don’t need to specify the dataSource as part of the binding itself (i.e. if it can shared across your sub-hierarchy), then you can still define your bindings in UXML through the UI Builder and only set the dataSource through code.

if you check the small sample… we assign the datasource from monobehaviour, we don’t use scriptable objects here

How is the binding checking for changes to the source value? Is it checking for changes every frame? Is it slow to have a lot of bindings?

Hi. maybe this docs page might help

I want to know how to bind data to treeview :thinking:

What is the “Data Source Path” in the “Bindings” section at the top of the UI Builder Inspector for? As I understand it, I use the three-dots menu and set a data source path for each property individually.

you can set up the data source path there if several properties are gonna be using the same value, just add the binding but leave the data source path empty, like in here:

or if that property is the only one using that data source path, just add it in the property and leave the general data source path section blank, both work

of you can point to the data path source (like a class) there at the top of the inspector, and then for each individual property bind the variable inside the class

1 Like

Thanks. I do think that’s a rather awkward design, but I very much appreciate your additional explanation.

1 Like

It’s mostly to avoid repeating yourself. Let’s say you have a data source like:

public class SplitScreen : ScriptableObject
{
    public PlayerInfo playerA;
    public PlayerInfo playerB;
}

When displaying the split screen, you might want to use the same UXML file to display the PlayerInfo for each player. That UXML file should care about where the PlayerInfo is coming from, so all bindings should stay relative to PlayerInfo and then you can use the dataSourcePath on the element to indicate which instance it should use. So something like:

<VisualElement data-source="Path.To.SplitScreen.asset">
    <VisualElement data-source-path="playerA">
        <!-- Nested document goes here -->
    </VisualElement>
    <VisualElement data-source-path="playerB">
        <!-- Nested document goes here -->
    </VisualElement>
</VisualElement>

I’m pretty new to UI Toolkit, so please forgive me if this is a dumb question. But wouldn’t that take me back to a unique data source path for each of the two VisualElements? How would the single Data Source Path at the top of the UI Builder Inspector be involved in that?

You can set the data-source-path on both elements and bindings and they will be concatenated until we find the closest data-source.

So the Data Source Path at the top of the UI Builder Inspector allows you to set the data-source-path for the element:

<VisualElement data-source-path="somePath"/>

And setting it for a property through the “Bindings” menu will add it to the binding instance instead:

<VisualElement>
    <Bindings>
        <DataBinding property="prop" data-source-path="somePath"/>
    </Bindings>
</VisualElement>

The key difference here is that setting the data-source-path on the element will affect the bindings on that element and potentially children of that element whereas setting it on the binding will only affect the binding.

I see. Thanks again.

Where is this documented?

Is there anywhere a working example of setting a two way binding at runtime?
I’m generating UI at runtime so assigning data sources beforehand is not doable for me, and I can’t seem to set up two way binding in any way, the link is always faling.