Search Unity

Hiding an element based on a dropdown

Discussion in 'UI Toolkit' started by andybak, Jan 19, 2020.

  1. andybak

    andybak

    Joined:
    Jan 14, 2017
    Posts:
    569
    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?

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. [CustomEditor(typeof(TankScript))]
    6. public class TankEditor : Editor
    7. {
    8.     public override VisualElement CreateInspectorGUI()
    9.     {
    10.         var visualTree = Resources.Load("tank_inspector_uxml")
    11.             as VisualTreeAsset;
    12.         var ve = visualTree.CloneTree();
    13.         ve.Q("enum-field").RegisterCallback<ChangeEvent<TankScript.MyEnum>>(
    14.             evt => {
    15.             ve.Q("tank-size-field").visible = (
    16.                 evt.newValue == TankScript.MyEnum.One);
    17.         });
    18.         return ve;
    19.     }
    20. }
    The only other relevant code is this:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class TankScript : MonoBehaviour
    4. {
    5.     public string tankName = "Tank";
    6.     public float tankSize = 1;
    7.     public enum MyEnum {Zero,One}
    8.     public MyEnum enumField = MyEnum.Zero;
    9. }
    and

    Code (XML):
    1.  
    2. <UXML xmlns:ui="UnityEngine.UIElements" xmlns:ue="UnityEditor.UIElements">
    3.     <ui:VisualElement name="row" class="container">
    4.         <ue:PropertyField binding-path="tankName" name="tank-name-field" />
    5.         <ue:PropertyField binding-path="tankSize" name="tank-size-field" />
    6.         <ue:PropertyField binding-path="enumField" name="enum-field" />
    7.     </ui:VisualElement>
    8. </UXML>
    9.  
     
  2. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    780
    Hello,

    Internally the PropertyField will only create a PopupField<string> (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:
    Code (CSharp):
    1. <ue:EnumField label="Enum Field" binding-path="enumField" name="enum-field" />
    Then your custom editor can register for
    ChangeEvent<System.Enum> 
    to catch changes:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. [CustomEditor(typeof(TankScript))]
    5. public class TankEditor : Editor
    6. {
    7.     public override VisualElement CreateInspectorGUI()
    8.     {
    9.         var visualTree = Resources.Load("tank_inspector_uxml")
    10.             as VisualTreeAsset;
    11.         var ve = visualTree.CloneTree();
    12.         ve.Q("enum-field").RegisterCallback<ChangeEvent<System.Enum>>(
    13.             evt => {
    14.             ve.Q("tank-size-field").visible = (
    15.                 (TankScript.MyEnum)evt.newValue == TankScript.MyEnum.One);
    16.         });
    17.         return ve;
    18.     }
    19. }
    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.
     
    Synaptein and andybak like this.
  3. andybak

    andybak

    Joined:
    Jan 14, 2017
    Posts:
    569
    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?
     
    Synaptein likes this.
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Definitely something to clear up in our docs. I'll make sure to add to our list of things for the docs review.
     
    Synaptein likes this.