How to connect two binding fields relative?

I has a MonoBehavior and I want to custom the inspector with UIElements:

public class MyData : MonoBehaviour
{
    public bool featureEnabled;
    public int featureParam;
}

I hope the ‘featureParam’ is visible only when ‘featureEnabled’ is true. So I write the Editor like this:

[CustomEditor(typeof(MyData))]
internal sealed class MyDataEditor : Editor
{
    private Toggle featureEnabled;
    private VisualElement featureParam;

    public override VisualElement CreateInspectorGUI()
    {
        var asset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
            "Assets/MyDataEditor.uxml");
        var root = asset.CloneTree();

        this.featureEnabled = root.Q<Toggle>("featureEnabled");
        this.featureParam = root.Q("featureParam");

        this.featureEnabled.RegisterValueChangedCallback(this.OnFeatureChanged);
        this.featureParam.SetEnabled(this.featureEnabled.value);

        return root;
    }

    private void OnFeatureChanged(ChangeEvent<bool> e)
    {
        // this.featureParam.visible = e.newValue;
        this.featureParam.SetEnabled(e.newValue);
    }
}

There has two problem:

  • When this.featureParam.visible set to false, the UI control is disappear but the space is still there.
  • There is no way to initialize the state about ‘featureParam’: The root is not bind before the ‘CreateInspectorGUI’ return.

Is there any best partice about this?

If you don’t want the space to stay, you could keep a reference to your root visual element and instead do a featureEnabled.RemoveFromHierarchy() when you don’t need it, then root.Add(featureEnabled) (or Insert) when you want it back.

You can get the property from your serializedObject directly like so in the CreateInspectorGUI:

var property = serializedObject.FindProperty("featureEnabled");
featureParam.SetEnabled(property.boolValue);

Yes, but ‘listen to the change event and initialize the states’ is a common pattern. The code somehow duplicates twice.
The ‘onChange’ handler use data from ‘ChangeEvent’, but the ‘initialize’ read from serializedObject.

It works in this way but I want to know if it is a proper way.

Hi, I have two question:

  • When I ‘featureEnabled.RemoveFromHierarchy()’, I have to add it back to the correct position? Or is there any way to achieve this, avoid record the slibing, as is a common task.
  • Is the sequence order of ‘OnEnable’ and ‘CreateInspectorGUI’ is guaranteed? So I can find the SerializedPropertys in ‘OnEnable’ and store in member field after used in ‘CreateInspectorGUI’

Binding operations will only happen once the element has been added to a panel, which has not yet happened in CreateInspectorGUI().
You could register to AttachToPanelEvent and do the initialization there.

Instead of adding to the root, you can add a simple (named) VisualElement parent to your “featureEnabled” that you would query, to easily know where it needs to be added without knowing about the hierarchy layout.

Is there a good idea I change the ‘style.display’ between ‘DisplayStyle.Flex’ and ‘DisplayStyle.None’, instead of changing the visible?

Yes absolutely, sorry about that, I should have suggested that actually, much simpler solution for that part of your problem :slight_smile: