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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Can't set objectReferenceValue on array items from custom editors

Discussion in 'Editor & General Support' started by DaCookie, May 13, 2019.

  1. DaCookie

    DaCookie

    Joined:
    Nov 4, 2014
    Posts:
    44
    I'm trying to make a custom editor for a component that contains an array of sprites, but it seems that the editor refuses to let me add items to this array.

    I’m making my own drag and drop operation resolution. If you add the two following scripts in your project, you'll get the inspector layout as in the screenshot linked to this post.

    So, if you drag a Sprite in the drag and drop area of the component, you'll see the array with 1 item during a frame, then resets to 0 item.
    I have the same issue on Unity 2017.4 and 2018.3.

    Does someone know why it happens and how can I fix it? Thanks in advance !

    Test this behavior in your projet by adding these scripts:

    Here is the code of my component:
    Code (CSharp):
    1. using UnityEngine;
    2. public class SpriteArrayTester : MonoBehaviour
    3. {
    4.     public Sprite[] sprites = { };
    5. }
    And here is my custom editor:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. [CustomEditor(typeof(SpriteArrayTester))]
    4. public class SpriteArrayTesterEditor : Editor
    5. {
    6.     private SerializedProperty _spritesArrayProperty = null;
    7.     private Object[] _referencesToAdd = null;
    8.  
    9.     private void OnEnable()
    10.     {
    11.         _spritesArrayProperty = serializedObject.FindProperty("sprites");
    12.     }
    13.  
    14.     public override void OnInspectorGUI()
    15.     {
    16.         // Adds object references if there's one or more.
    17.         // I need to do that at a different moment of the drag and drop resolution to avoid errors.
    18.         AddObjectReferences(_spritesArrayProperty);
    19.  
    20.         // Draw drag and drop area
    21.         Rect dropArea = EditorGUILayout.GetControlRect(false, 200f);
    22.         GUI.Box(dropArea, "Drag and drop sprites here...");
    23.         ManageDragAndDrop(dropArea);
    24.  
    25.         // Display array elements
    26.         EditorGUILayout.LabelField("Array content (" + _spritesArrayProperty.arraySize + ")", EditorStyles.boldLabel);
    27.         for(int i = 0; i < _spritesArrayProperty.arraySize; i++)
    28.         {
    29.             SerializedProperty itemProperty = _spritesArrayProperty.GetArrayElementAtIndex(i);
    30.             EditorGUILayout.LabelField(i + ": " + itemProperty.displayName);
    31.         }
    32.     }
    33.  
    34.     private void ManageDragAndDrop(Rect dropArea)
    35.     {
    36.         switch (Event.current.type)
    37.         {
    38.             // If user dropped something out of the area, ignore the event
    39.             case EventType.DragUpdated:
    40.             case EventType.DragPerform:
    41.             if (!dropArea.Contains(Event.current.mousePosition))
    42.                 break;
    43.  
    44.             DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
    45.  
    46.             if (Event.current.type == EventType.DragPerform)
    47.             {
    48.                 // Accept drag and drop operation, and store dragged objects references
    49.                 DragAndDrop.AcceptDrag();
    50.                 _referencesToAdd = DragAndDrop.objectReferences;
    51.                 Debug.Log("Accepting drag , nb references to add = " + _referencesToAdd.Length);
    52.             }
    53.             break;
    54.         }
    55.     }
    56.  
    57.     private void AddObjectReferences(SerializedProperty arrayProperty)
    58.     {
    59.         if(_referencesToAdd != null)
    60.         {
    61.             foreach (Object draggedObject in _referencesToAdd)
    62.             {
    63.                 int index = arrayProperty.arraySize;
    64.                 // Add an item at the last index
    65.                 arrayProperty.InsertArrayElementAtIndex(index);
    66.                 // Set the object reference to the added item
    67.                 arrayProperty.GetArrayElementAtIndex(index).objectReferenceValue = draggedObject;
    68.                 Debug.Log("Adding object reference = " + draggedObject.name + " at index " + index + ", reference is: " + arrayProperty.GetArrayElementAtIndex(index).objectReferenceValue);
    69.             }
    70.  
    71.             // Apply changes
    72.             serializedObject.ApplyModifiedProperties();
    73.             _referencesToAdd = null;
    74.         }
    75.     }
    76. }
    Thanks in advance ! :)
     

    Attached Files:

    Last edited: May 13, 2019
  2. DaCookie

    DaCookie

    Joined:
    Nov 4, 2014
    Posts:
    44
    I tested something (not a definitive solution) that works, but I have another issue.

    First, I saw that changing the
    DragAndDrop.visualMode
    value changes the behavior: if I use
    DragAndDropVisualMode.Rejected
    or
    DragAndDropVisualMode.None
    , absolutely nothing happens.

    So, I tried to delay the drag and drop resolution and the array copy. It works, new items stay in the array... but they're always null. Even by assigning items'
    objectReferenceValue
    property.

    Here is my new code:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. [CustomEditor(typeof(SpriteArrayTester))]
    4. public class SpriteArrayTesterEditor : Editor
    5. {
    6.     private SerializedProperty _spritesArrayProperty = null;
    7.     private Object[] _referencesToAdd = null;
    8.     private int timer = 0;
    9.  
    10.     private void OnEnable()
    11.     {
    12.         _spritesArrayProperty = serializedObject.FindProperty("sprites");
    13.         _referencesToAdd = null;
    14.     }
    15.  
    16.     public override void OnInspectorGUI()
    17.     {
    18.         // Adds object references if there's one or more.
    19.         // I need to do that at a different moment of the drag and drop resolution to avoid errors.
    20.         AddObjectReferences(_spritesArrayProperty);
    21.  
    22.         // Draw drag and drop area
    23.         Rect dropArea = EditorGUILayout.GetControlRect(false, 200f);
    24.         GUI.Box(dropArea, "Drag and drop sprites here...");
    25.         ManageDragAndDrop(dropArea);
    26.  
    27.         // Display array elements
    28.         EditorGUILayout.LabelField("Array content (" + _spritesArrayProperty.arraySize + ")", EditorStyles.boldLabel);
    29.         for (int i = 0; i < _spritesArrayProperty.arraySize; i++)
    30.         {
    31.             SerializedProperty itemProperty = _spritesArrayProperty.GetArrayElementAtIndex(i);
    32.             EditorGUILayout.LabelField("[" + i + "] " + itemProperty.displayName + ": " + (itemProperty.objectReferenceValue != null ? itemProperty.objectReferenceValue.name : "null"));
    33.         }
    34.  
    35.         EditorUtility.SetDirty(serializedObject.targetObject);
    36.     }
    37.  
    38.     private void ManageDragAndDrop(Rect dropArea)
    39.     {
    40.         switch (Event.current.type)
    41.         {
    42.             // If user dropped something out of the area, ignore the event
    43.             case EventType.DragUpdated:
    44.             case EventType.DragPerform:
    45.             if (!dropArea.Contains(Event.current.mousePosition))
    46.                 break;
    47.  
    48.             DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
    49.  
    50.             if (Event.current.type == EventType.DragPerform)
    51.             {
    52.                 // Accept drag and drop operation, and store dragged objects references
    53.                 DragAndDrop.AcceptDrag();
    54.                 _referencesToAdd = DragAndDrop.objectReferences;
    55.                 Debug.Log("Accepting drag , nb references to add = " + _referencesToAdd.Length);
    56.             }
    57.             break;
    58.         }
    59.     }
    60.  
    61.     private void AddObjectReferences(SerializedProperty arrayProperty)
    62.     {
    63.         if (_referencesToAdd != null)
    64.         {
    65.             Debug.Log("References to add detected");
    66.  
    67.             // Wait 10 UI refresh turns
    68.             if(timer < 10)
    69.             {
    70.                 timer++;
    71.                 Debug.Log("Increase timer: " + timer);
    72.                 return;
    73.             }
    74.  
    75.             timer = 0;
    76.             foreach (Object draggedObject in _referencesToAdd)
    77.             {
    78.                 int index = arrayProperty.arraySize;
    79.                 // Add an item at the last index
    80.                 arrayProperty.InsertArrayElementAtIndex(index);
    81.                 // Set the object reference to the added item
    82.                 arrayProperty.GetArrayElementAtIndex(index).objectReferenceValue = draggedObject;
    83.                 Debug.Log("Adding object reference = " + draggedObject.name + " at index " + index + ", reference is: " + arrayProperty.GetArrayElementAtIndex(index).objectReferenceValue);
    84.             }
    85.  
    86.             // Apply changes
    87.             serializedObject.ApplyModifiedProperties();
    88.             _referencesToAdd = null;
    89.         }
    90.     }
    91. }