Search Unity

Issues with InspectorElement

Discussion in 'UI Toolkit' started by Chris-Trueman, Jun 8, 2020.

  1. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    I am trying to create an editor window for an Item/Object database.

    I have a base item class that inherits from ScriptableObject. I have a few other classes that extend the item class. I have setup all the custom inspector's so they work great when selecting the assets.

    The problem begins when I try to use the InspectorElement within an editor window that displays all the items in a list. I am binding and unbinding each object when you select it in the list, so I can edit the items from there. It doesn't quite update the InspectorElement fully. It will leave parts of the other custom editors displayed when selecting an object with a different backing type, and even when I select a different object with the same backing type displayed, it doesn't update the values displayed that are unique to that type.

    This is the code I am using to attempt to change the item displayed. This should work but it doesn't.
    Code (CSharp):
    1. private void ItemList_onSelectionChange(IEnumerable<object> obj)
    2. {
    3.         var element = obj.ElementAt(0);
    4.         itemInspector.Unbind();
    5.         currentItem = element as Item;
    6.         itemInspector.Bind(new SerializedObject(currentItem));
    7.         itemInspector.MarkDirtyRepaint();
    8. }
    9.  
    I have a work around that works fine, it just doesn't make sense because I should be able to unbind the old data and then bind the new data so it displays the correct inspector.
    Code (CSharp):
    1. private void ItemList_onSelectionChange(IEnumerable<object> obj)
    2. {
    3.         var item = rootVisualElement.Q<VisualElement>("ItemDisplay");
    4.         item.Remove(itemInspector);
    5.         var element = obj.ElementAt(0);
    6.         itemInspector = new InspectorElement();
    7.         currentItem = element as Item;
    8.         itemInspector.Bind(new SerializedObject(currentItem));
    9.         item.Add(itemInspector);
    10. }
    11.  
    As you can see I am removing the InspetorElement, creating a new one, binding the item to it, then adding the new InspectorElement to the display.

    Not sure if this is a bug or I'm doing it wrong.
     
  2. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    I would look at ListView.bindItem() to bind new items or ListView.Refresh() to update the list when the source changes.
     
  3. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    Actually a call to Refresh should be enough.
     
  4. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    The ListView works fine, it binds quite nicely. The problem is with InspectorElement.

    Let me give you the layout of what I'm doing.

    I have a ListView on the left side of the window that lists all the items, it has a drop down that allows me to select different categories of items, this all works fine using one ListView and two List's. One list holds all the items, the other is the currently displayed items. Modifying that list and calling Refresh works great. The ListView's items are simply an Icon and a label for each item.

    On the right side I have the InspectorElement. When you select an item in the ListView it unbinds what is currently bound to the InspectorElement and then binds the newly selected item. This is where it has the issue described above.

    After reading my original post I realize that the explanation of the functionality was unclear, sorry for that.
     
  5. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    Can you copy-paste your declaration of class Item please? Is it a ScriptableObject?
     
  6. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    The custom inspector's work fine out side of the custom window. It's like the InspectorElement isn't quite rebuilding itself when you unbind/bind. Everything is fine if I only use the Item class, but starts to have issues when I use a class that inherits from Item.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class Item : ScriptableObject
    5. {
    6.     [Tooltip("Name of the item.")]
    7.     public string itemName;
    8.     [ShowOnly, Tooltip("The itemID, should be unique and set by the system. Copy it via the context menu.")]
    9.     public int itemID = 0;
    10.     [Tooltip("The item category.")]
    11.     public ItemCategory itemCategory;
    12.     [Multiline, Tooltip("Description of the item.")]
    13.     public string itemDesc;
    14.     [Tooltip("Icon that will be shown in the UI.")]
    15.     public Sprite uiIcon;  
    16.     [Tooltip("Is the item unique, can we only hold one?")]
    17.     public bool unique;
    18.     [Tooltip("Can the item be placed in the world?")]
    19.     public bool placeable;
    20.     [Tooltip("Item prefab that will be spawned in world. If left null it will spawn as a pickup.")]
    21.     public GameObject itemPrefab;
    22.     [Tooltip("The scale the pickup will be when spawned.")]
    23.     public float pickupScale = 1.0f;
    24.     [Tooltip("The offset of the pickup collider. Used for sprites that do not have their pivot in the center.")]
    25.     public Vector2 pickupColliderOffset;
    26.     [Tooltip("The radius of the pickup collider. Not sure if this is needed!")]
    27.     public float pickupColliderRadius = 0.5f;
    28.  
    29.     public ItemData GetData(int count = 1)
    30.     {
    31.         return new ItemData(itemID, count, unique ? Guid.NewGuid().GetHashCode() : 0);
    32.     }
    33.  
    34. #if UNITY_EDITOR
    35.     protected void OnValidate()
    36.     {
    37.         //Debug.Log("Validate");
    38.         if (itemID == 0)
    39.         {
    40.             itemID = Guid.NewGuid().GetHashCode();
    41.             UnityEditor.AssetDatabase.Refresh();          
    42.         }
    43.  
    44.         if (itemPrefab)
    45.         {
    46.             //Debug.Log(itemPrefab);
    47.             ItemObjectBase iob = itemPrefab.GetComponent<ItemObjectBase>();
    48.             if (iob && iob.itemID != itemID)
    49.             {
    50.                 iob.itemID = itemID;
    51.                 UnityEditor.AssetDatabase.Refresh();
    52.             }
    53.         }
    54.     }
    55.  
    56.     [ContextMenu("Copy ItemID to Clipboard")]
    57.     protected void CopyItemID()
    58.     {
    59.         UnityEditor.EditorGUIUtility.systemCopyBuffer = itemID.ToString();
    60.         Debug.Log("ItemID Copied to Clipboard!");
    61.     }
    62. #endif
    63.  
    64.     public override string ToString()
    65.     {
    66.         return $"Name: {itemName}, ID: {itemID}, Category: {itemCategory}";
    67.     }
    68. }