Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


Introduction to SerializedObject data binding

Get started with SerializedObject data binding.
Read time 7 minutesLast updated 3 days ago

You can use the SerializedObject data binding system to bind to serialized properties. This means you can bind visual elements to the following objects that are compatible with the Serialization system:
  • User-defined
    ScriptableObject
    classes
  • User-defined
    MonoBehaviour
    classes
  • Native Unity component types
  • Native Unity asset types
  • Primitive C# types such as
    int
    ,
    bool
    , or
    float
    .
  • Native Unity types such as
    Vector3
    ,
    Color
    , or
    Object
    .

Value binding

You can only bind the
value
property of visual elements that implement the
INotifyValueChanged
interface. For example, you can bind
TextField.value
to a
string
, but you can't bind
TextField.name
to a
string
.
You can bind between an object and any visual element that either derives from
BindableElement
or implements the
IBindable
interface.

Create a binding

To create a binding, either call
Bind()
or
BindProperty()
.

Call
Bind()

You can call
Bind()
to bind an element to a SerializedObject. Before you bind an element, you must set the binding path and create a SerializedObject.
Use this method if you don't have easy access to the
SerializedProperty
for the binding. Refer to Create a binding with a C# script for an example.
The
Bind()
extension method sets up an entire hierarchy of visual elements with specified
bindingPath
properties. You can call the
Bind()
method on a single element or the parent of the hierarchy that you want to bind. For example, you can call
Bind()
on the
rootVisualElement
of an Editor window. This binds all child elements with specified
bindingPath
properties.
Don't call
Bind
from the
Editor.CreateInspectorGUI
or
PropertyDrawer.CreatePropertyGUI
override.
Bind
is called automatically on the visual elements that these methods return.

Call
Unbind()

The
Unbind()
method stops the value tracking for the element and all its direct and indirect child elements. In general, you don't need to call
Unbind()
because tracking stops when a user closes the Inspector or Editor window. Call
Unbind()
if you must bind elements to different targets in their lifetimes.
If you construct an
InspectorElement
in C# by calling its constructor, binding occurs during the constructor call. If you want to rebind an
InspectorElement
after it has been constructed, you must call
Unbind()
and then either call
Bind()
explicitly or let a bind operation from a parent create a binding.

Set binding path

If you call
Bind()
to create the binding, you must set the visual element's binding path to the property name of the object that you want to bind to.
For example:
  • If you have the following component script:
    using UnityEngine;public class MyComp : MonoBehaviour{ [SerializeField] int m_Count;}
    To bind your visual element to
    m_Count
    , set the binding path to
    m_Count
    .
  • If you want to bind a visual element to a GameObject's name property, which is
    m_Name
    , set the binding path to
    m_Name
    .
You can set the binding path in UI Builder, UXML, or with a C# script:

Call
BindProperty()

You can call
BindProperty()
to bind an element to a
SerializedProperty
directly.
Use this method if you already have a
SerializedProperty
object, and especially if you traverse the properties of a
SerializedObject
to build a UI dynamically. Refer to Bind without the binding path for an example.

Bind elements to nested properties

You can bind a visual element to nested properties in the source object. To do so, combine the binding path of an element with the binding path of the first ancestor. Use this method with the following elements:
Refer to Bind to nested properties for an example.

Receive callbacks when values change

You can create a binding to receive a callback when a bound serialized property changes. To do so, leverage the
TrackPropertyValue()
extension method, which is available to any
VisualElement
. This registers a callback that executes when the provided
SerializedProperty
changes. Refer to Receive callbacks when a serialized property changes for an example.
You can also create a binding to receive a callback when any properties of the bound serialized object change. To do so, leverage the
TrackSerializedObjectValue()
extension method, which is available to any
VisualElement
. This registers a callback that executes when the provided
SerializedObject
changes. Refer to Receive callbacks when any properties change for an example.

Bind custom elements

You can create custom elements and bind them to serialized properties through the value binding system.
To create bindable custom elements:
  1. Declare a custom element.
  2. Inherit the element from
    BindableElement
    or implement the
    IBindable
    interface.
  3. Implement the
    INotifyValueChanged
    interface.
  4. Implement the
    SetValueWithoutNotify()
    method of the
    INotifyValueChanged
    interface.
  5. Implement the
    value
    property accessors of the
    INotifyValueChanged
    interface.
Refer to Create and style a custom control for an example.
Note
You can't bind custom data types directly to custom elements because the binding system only allows you to bind an element to a type supported by SerializedPropertyType of
enum
. This means you can't define a class or structure, for example, a struct called
MyStruct
, and bind it to an element that implements
INotifyValueChanged<MyStruct>
. However, you can bind to serializable nested properties of custom data types. This includes polymorphic serialization (when a field uses the
[SerializeReference]
attribute
). Refer to Bind a custom control to custom data type for an example.

Bind time

Based on the type of UI you create, binding occurs at various times. This is called bind time.
The following table describes the bind time of a control:

Condition

Automatic bind time (assuming binding path was set)

An
InspectorElement
constructed in C#
During the constructor call
A child element that is under the return value of
CreateInspectorGUI()
or
CreatePropertyGUI()
when those methods return
After
CreateInspectorGUI()
or
CreatePropertyGUI()
returns
A child element that is under an element when
Bind()
or
BindProperty()
is called on the parent element
During the
Bind()
or
BindProperty()
call
OtherNo automatic binding; you must bind the element or one of its parents manually
The following are best practices when creating a binding regarding bind time:
  • If you create a custom
    Editor
    or custom
    PropertyDrawer
    , set the elements' binding paths instead of calling
    Bind()
    or
    BindProperty()
    on any visual elements that are in the visual tree by the end of the body of
    CreateInspectorGUI()
    or
    CreatePropertyGUI()
    . These elements are bound automatically after
    CreateInspectorGUI()
    or
    CreatePropertyGUI()
    returns. However, if you add any elements to the visual tree after that point, call
    Bind()
    or
    BindProperty()
    to bind them.
  • If you create any other type of UI, call
    Bind()
    or
    BindProperty()
    regardless of the time at which the elements get added to the visual tree. If you call
    Bind()
    or
    BindProperty()
    and bind multiple controls at the same time, set the binding path of each control and then call
    Bind()
    on the lowest-level parent element that encompasses all the controls.
    Bind()
    binds the element on which it's called if it has a binding path and recursively binds all its child elements if they have binding paths. To prevent a negative performance impact, don't bind a visual element with the
    Bind()
    method more than once.

Bind to a serialized property backing field

When you use an auto-property, the compiler automatically generates a backing field with a name as
<PropertyName>k__BackingField
. This field is not explicitly visible in your code but can be referenced if necessary, as in binding scenarios.
For example, the following example defines an auto-property
SomeProp
and serializes it:
[field: SerializeField] public float SomeProp { get; private set; }
The compiler generates the following backing field:
[SerializedField]private float <SomeProp>k__BackingField;public float SomeProp{ get => <SomeProp>k__BackingField; set => <SomeProp>k__BackingField = value;}
To bind to
<SomeProp>k__BackingField
in UXML, you must escape
< 
and
>
because they're reserved for tags. For example, set the
binding-path
as follows:
<editor:PropertyField name="some-prop" binding-path="&lt;SomeProp&gt;k__BackingField"/>

Binding examples

Try the following examples to learn how to code with data binding:

Additional resources