Hiding an element based on a dropdown

My first attempt at using UI Elements so I thought I’d start with something really simple - hiding a field based on a choice in another field.

I modified the custom inspector from the Tank example, adding an enum to TankScript.

This is what my research would indicate should work. However my call back is never triggered. I’ve tried with just a debug.log in there, a separate method instead of an inline lambda. I’ve tried changing the class parameter to ChangeEvent to various things (the docs are especially unhelpful on what this parameter should be).

The callback is never fired. Any ideas?

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

[CustomEditor(typeof(TankScript))]
public class TankEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var visualTree = Resources.Load("tank_inspector_uxml")
            as VisualTreeAsset;
        var ve = visualTree.CloneTree();
        ve.Q("enum-field").RegisterCallback<ChangeEvent<TankScript.MyEnum>>(
            evt => {
            ve.Q("tank-size-field").visible = (
                evt.newValue == TankScript.MyEnum.One);
        });
        return ve;
    }
}

The only other relevant code is this:

using UnityEngine;

public class TankScript : MonoBehaviour
{
    public string tankName = "Tank";
    public float tankSize = 1;
    public enum MyEnum {Zero,One}
    public MyEnum enumField = MyEnum.Zero;
}

and

<UXML xmlns:ui="UnityEngine.UIElements" xmlns:ue="UnityEditor.UIElements">
    <ui:VisualElement name="row" class="container">
        <ue:PropertyField binding-path="tankName" name="tank-name-field" />
        <ue:PropertyField binding-path="tankSize" name="tank-size-field" />
        <ue:PropertyField binding-path="enumField" name="enum-field" />
    </ui:VisualElement>
</UXML>

Hello,

Internally the PropertyField will only create a PopupField (since it may represent a C++ enum from the core engine with no C# representation). We may add the ability to detect if this property is a managed enum at a later time.

Meanwhile you can directly specify that you’d like an enum field to be created in your hierarchy:

<ue:EnumField label="Enum Field" binding-path="enumField" name="enum-field" />

Then your custom editor can register for ChangeEvent<System.Enum> to catch changes:

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
[CustomEditor(typeof(TankScript))]
public class TankEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var visualTree = Resources.Load("tank_inspector_uxml")
            as VisualTreeAsset;
        var ve = visualTree.CloneTree();
        ve.Q("enum-field").RegisterCallback<ChangeEvent<System.Enum>>(
            evt => {
            ve.Q("tank-size-field").visible = (
                (TankScript.MyEnum)evt.newValue == TankScript.MyEnum.One);
        });
        return ve;
    }
}

Without this you can still register for ChangeEvent<string> and either convert the string value to enum or use the popupField.index property to convert that back to the enum.

2 Likes

Wow. Thanks for this.

Out of interest - is there any chance I could have figured this out for myself without a reasonably deep knowledge of Unity internals? I had no inkling there was a distinction between C++ enums and C# enums!

Is this just black magic or is there a route to a proper understanding of this stuff?

I think maybe the docs around ChangeEvent could give some guidance as to how to use the type parameter. Would you agree?

1 Like

Definitely something to clear up in our docs. I’ll make sure to add to our list of things for the docs review.

1 Like