Version: 2021.3+
This example demonstrates how to use the binding-path attribute of a BindableElement in UXML to bind fields to nested properties of a SerializedObject.
This example creates a custom InspectorA Unity window that displays information about the currently selected GameObject, asset or project settings, allowing you to inspect and edit the values. More info
See in Glossary UI with the following:
You can find the completed files that this example creates in this GitHub repository.
This guide is for developers familiar with the Unity Editor, UI Toolkit, and C# scripting. Before you start, get familiar with the following:
BindableElementPropertyFieldCreate a C# script to define a class for a tank that has health values to make it destructible.
Create a project in Unity with any template.
In your Project windowA window that shows the contents of your Assets folder (Project tab) More info
See in Glossary, create a folder named bind-nested-properties to store all the files.
Create a C# script named DestructibleTankScript.cs and replace its content with the following:
using System;
using UnityEngine;
using UnityEngine.Serialization;
[Serializable]
public struct Health
{
public int armor;
public int life;
}
[ExecuteInEditMode]
public class DestructibleTankScript : MonoBehaviour
{
public string tankName = "Tank";
public float tankSize = 1;
public Health health;
private void Update()
{
gameObject.name = tankName;
gameObject.transform.localScale = new Vector3(tankSize, tankSize, tankSize);
}
public void Reset()
{
health.armor = 100;
health.life = 10;
}
}
Create a UXML file with a BindableElement. Set the BindableElement’s binding-path to the health property and set each child element’s binding-path of the BindableElement to the armor and life properties of health.
In the bind-nested-properties folder, create a folder named Editor.
In the Editor folder, create a USS file named tank_inspector_styles.uss and replace its contents with the following:
.container {
background-color: rgb(80, 80, 80);
flex-direction: column;
}
Label {
background-color: rgb(80, 80, 80);
}
TextField:hover {
background-color: rgb(255, 255, 0);
}
FloatField {
background-color: rgb(0, 0, 255);
}
Create a UI Document named destructible_tank_editor.uxml and replace its contents with the following:
<UXML xmlns="UnityEngine.UIElements" xmlns:ue="UnityEditor.UIElements">
<Style src="tank_inspector_styles.uss"/>
<VisualElement name="row" class="container">
<Label text="Tank Script - Custom Inspector" />
<ue:PropertyField binding-path="tankName" name="tank-name-field" />
<ue:PropertyField binding-path="tankSize" name="tank-size-field" />
<BindableElement binding-path="health">
<ue:PropertyField binding-path="armor"/>
<ue:PropertyField binding-path="life"/>
</BindableElement>
</VisualElement>
</UXML>
Create a C# script that registers a custom Editor for the DestructibleTankScript.
Create a C# script named DestructibleTankEditor.cs and replace its content with the following:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
[CustomEditor(typeof(DestructibleTankScript))]
public class DestructibleTankEditor : Editor
{
[SerializeField]
VisualTreeAsset visualTreeAsset;
public override VisualElement CreateInspectorGUI()
{
return visualTreeAsset.CloneTree();
}
}
Select DestructibleTankEditor.cs in the Project window.
Drag destructible_tank_editor.uxml to Visual Tree Asset in the Inspector.
health.armor and health.life properties. If you change the values in the Inspector, the values of the underlying properties change.