Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Completely lost.

Discussion in 'UI Toolkit' started by Undertaker-Infinity, May 17, 2021.

  1. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    I've been trying to get a basic UI Toolkit editor working for weeks in 2020.2 and I'm completely lost.

    I have no trouble creating a simple UI. UXML works fine, even though many XML fields are left unexplained.
    I managed to display it as an inspector without much trouble, but I could not bind it to the GameObject. All explanations found online pointed to ScriptableObjects, so instead I'm trying that route.

    I did check https://docs.unity3d.com/Manual/UIE-Binding.html and followed the UXML example. The window displays, but it doesn't seem to be bound to any instance of the scriptable object. This is no surprise, since the example code never mentions the scriptable object class to be bound.
    I've looked into every page of the documentation and a ton of examples and a lot of it shows how to manually bind field per field while creating the field in immediate mode, which I think it's missing the point of having UXML. If I can't use UXML, I'd go back to the old editor UI which has better documentation and more examples floating around. I'll want array/lists later, and doing all that management does sound like a lot of overkill, which I thought binding was supposed to solve quickly by binding a whole tree.

    Can anyone just show how this should be done? I've stripped everything to a simple string.
    I want to be able to open the SO in the editor window, edit and save the changes. If I can get this working, I think I can extrapolate to more complex cases.

    Thanks.

    This is my UXML

    ActorBehaviour.uxml
    Code (CSharp):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
    2.     <ui:Label text="Label" display-tooltip-when-elided="true" />
    3.     <ui:TextField picking-mode="Ignore" label="Text Field" value="filler text" text="filler text" name="stages" binding-path="stages" />
    4. </ui:UXML>
    5.  

    ActorBehaviourEditor.uxml
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEditor.UIElements;
    4. using UnityEngine.UIElements;
    5.  
    6.  
    7. namespace UIElementsExamples
    8. {
    9.    public class ActorBehaviourEditor : EditorWindow
    10.    {
    11.        [MenuItem("Window/Actor Behaviour Editor")]
    12.        public static void ShowDefaultWindow()
    13.        {
    14.            var wnd = GetWindow<ActorBehaviourEditor>();
    15.            wnd.titleContent = new GUIContent("Actor Behaviour Editor");
    16.        }
    17.  
    18.        public void OnEnable()
    19.        {
    20.            var root = this.rootVisualElement;
    21.            var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ActorBehaviour/Editor/ActorBehaviour.uxml");
    22.            visualTree.CloneTree(root);
    23.            OnSelectionChange();
    24.        }
    25.    
    26.        public void OnSelectionChange()
    27.        {
    28.            GameObject selectedObject = Selection.activeObject as GameObject;
    29.            if (selectedObject != null)
    30.            {
    31.                // Create serialization object
    32.                SerializedObject so = new SerializedObject(selectedObject);
    33.                // Bind it to the root of the hierarchy. It will find the right object to bind to...
    34.                rootVisualElement.Bind(so);
    35.            }
    36.            else
    37.            {
    38.                // Unbind the object from the actual visual element
    39.                rootVisualElement.Unbind();
    40.              
    41.                // Clear the TextField after the binding is removed
    42.                // (this code is not safe if the Q() returns null)
    43.                rootVisualElement.Q<TextField>("stages").value = "";
    44.            }
    45.        }
    46.    }
    47. }
     
  2. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,256
    If you want it in an editor window and not the inspector, the UITK team gave us the InspectorElement. https://docs.unity3d.com/ScriptReference/UIElements.InspectorElement.html

    You would create a custom inspector for your MonoBehaviour or ScriptableObject and then use the InspectorElement to display the object.

    I used this for an Item Database editor window. It lists all the items in the window and when you select one it displays its inspector in the InspectorElement beside the list.
     
  3. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    InspectorElement generates a new field.

    I already have the fields in UXML. I have asked how to bind them.
     
  4. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,256
    Take the UXML and make it a custom inspector then.

    How you are binding it is how you would do it, but it is problematic. I have not done it reliably in an editor window other than using an InspectorElement.
     
  5. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,256
    Oh one other thing, make sure that the binding-path is the exact name of the field you are binding it to.
     
  6. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    Argh. I think I'll revert to IMGUI and try UIElements again in a year or two. Thanks.
     
  7. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    Wait, how would I do it in a custom inspector? I had abandoned this path because all the examples I find go for an EditorWindow.
    The examples I found for custom inspector either did not use UXML or would bind every field one by one finding them by id.
     
  8. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    Code (CSharp):
    1. [CustomEditor(typeof(WhateverData))]
    2. public class YourStuff : Editor
    3. {
    4.     WhateverData data;
    5.     VisualElement root;
    6.  
    7.     public void OnEnable()
    8.     {
    9.         data = (WhateverData)target;
    10.         root = new VisualElement();
    11.  
    12.         VisualTreeAsset visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/…/Editor/YourStuff.uxml");
    13.         visualTree.CloneTree(root);
    14.  
    15.         StyleSheet stylesheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/…/Editor/YourStuff.uss");
    16.         root.styleSheets.Add(stylesheet);
    17.     }
    18.  
    19.     public override VisualElement CreateInspectorGUI()
    20.     {
    21.         var labels = root.Query().Children<Label>().ToList();
    22.         for (var i = 0; i < labels.Count; i++)
    23.         {
    24.             var label = labels[i];
    25.             labels[i].RegisterCallback<MouseDownEvent>( (evt) => { Debug.Log(label.name); } )
    26.         }
    27.         return root;
    28.     }
    29. }
    Also I find the samples to be pretty useful:
    upload_2021-5-17_22-0-54.png

    For you it should say "Import" or "Download" I don't remember.
    To view the samples: Window > UI Toolkit > Samples > ...
    To view the code: Assets > Samples > UI Toolkit > [version] > UI Toolkit Examples > ...

    As for binding, I think this thread could help.
     
    Last edited: May 18, 2021
    Undertaker-Infinity likes this.
  9. Undertaker-Infinity

    Undertaker-Infinity

    Joined:
    May 2, 2014
    Posts:
    112
    Thanks man. I burned out so much on this that I decided to give it a long break, and when I came back, 2021.2 had launched and the docs now actually have a step-by-step guide to building UIE inspectors.

    It looks pretty much like what you've shown here (with auto-binding as it was promised) and I got it working on the first try, in both an editor window and the regular inspector. The lists also render nicely now, with optional drag handles for reordering and buttons for adding/removing. I noticed the changelog had fixes for a ton of things that were messing up my attempts.

    Nested list reordering is broken currently but hey, making progress. I guess when features get announced out of preview, there's still a couple years left until they're actually usable.

    Now I can move on to do nice inspectors quickly!
    Thanks again.