How to refresh custom inspector when variable changed?

Hello there!

We just upgraded to the new Unity 2022.3.0 LTS for our new project and with this also to UIElements.
We’re now trying to create a custom inspector that draws either the default inspector or a label. Which one of these it should render is dependent of a bool inside the component.
The problem is, that CreateInspectorGUI is only called once and not each time the view refreshes like the old OnGUI was. So when the bool changes, the custom inspector is not updated.
We probably need to use binding in some way but … how? It’s not quite clear how it should be implemented.

Here is pseudo code that explains what we’re trying to achieve.

[CustomEditor(typeof(MyComponent))]
public class MyComponentInspector : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var myComponent = target as MyComponent;

        //This if statement should be called when myComponent.myBool changed.
        if(myComponent.myBool)
        {
            //draw the default inspector
            return base.CreateInspectorGUI();
        }
        else
        {
            //render some label text
        }
    }
}

First of all, calling “base.CreateInspectorGUI()” will not show the default inspector. To do that you need to use
“InspectorElement.FillDefaultInspector”, like so

var defaultInspector = new VisualElement();
InspectorElement.FillDefaultInspector(defaultInspector, serializedObject, this);

Now for the main question, you basically have to create both views, and then use
“TrackPropertyValue” to show and hide the appropriate view.

Here’s some quick and dirty code that illustrates this.

public override VisualElement CreateInspectorGUI()
{
    var container = new VisualElement();
   
    var defaultInspector = new VisualElement();
    InspectorElement.FillDefaultInspector(defaultInspector, serializedObject, this);
   
    var labelText = new Label("Hello");
   
    container.Add(defaultInspector);
    container.Add(labelText);
   
    var boolSerializedProperty = serializedObject.FindProperty("myBool");
    
    container.TrackPropertyValue(boolSerializedProperty, _ => {
        var myBoolValue = boolSerializedProperty.boolValue;
        if (myBoolValue) {
           //show default inspector
            defaultInspector.style.display = DisplayStyle.Flex;
            labelText.style.display = DisplayStyle.None;
        }
        else {
           //show label
            defaultInspector.style.display = DisplayStyle.None;
            labelText.style.display = DisplayStyle.Flex;
        }
    });
    return container;
}
1 Like

Thank you for your answer, that helps a lot!

One additional answer:
We’re working with serialized auto-properties like so. Are those supported by UIElements? Because when using FindProperty on it, it returns null. We even tried to get the backing field of the auto property, but that still returns null.

[field: SerializeField]
public bool MyBool { get; private set; }

You need to get the backing field as the property itself isn’t what’s being drawn/serialised. I would look at the serialised data to determine the serialised property name, or find the field in the inspector and Right Click → Copy Property Path.