unity-game-enginecustom-attributesunity-editor

UnityEditor: System.ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint


I'm trying to implement displaying the properties of an object added to an ObjectField via an attribute. Through a custom editor, I can, but I'm tired of creating an editor for each new class. I want through attribute.

Code for attribute:

[System.AttributeUsage(System.AttributeTargets.Field)]
public class DisplayPropertiesAttribute : PropertyAttribute
{
    public DisplayPropertiesAttribute() { }
}

Code for drawer:

[CustomPropertyDrawer(typeof(DisplayPropertiesAttribute))]
    public class DisplayPropertiesDrawer : PropertyDrawer
    {
        private Editor editor;
        private bool foldout;

        /// <summary>
        /// Overrides GUI drawing for the attribute
        /// </summary>
        /// <param name="position"><see cref="Rect"/> fields to activate validation</param>
        /// <param name="property">Serializedproperty the object</param>
        /// <param name="label">Displaу field label</param>
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {// Check if this is reference type property
            if (property.propertyType != SerializedPropertyType.ObjectReference)
            {
                // If field is not reference, show error message.            
                var style = new GUIStyle(EditorStyles.objectField);
                style.normal.textColor = Color.red;

                // Display label with error message
                EditorGUI.LabelField(position, label, new GUIContent($"{property.propertyType} is not a reference type"), style);
                return;
            }

            // If there is already an editor, add a foldout icon
            if (editor) { foldout = EditorGUI.Foldout(position, foldout, new GUIContent()); }

            // Start blocking change checks
            EditorGUI.BeginChangeCheck();
            // Display a ObjectField
            EditorGUI.ObjectField(position, property, label);
            // If changes were made to the contents of the field,
            // or the reference is empty, there is an editor,
            // or the reference is there but there is no editor
            if (EditorGUI.EndChangeCheck() || (property.objectReferenceValue ^ editor))
            {
                // Create an editor for the object pointed to by the reference, even if reference is empty
                editor = Editor.CreateEditor(property.objectReferenceValue);
            }

            // If foldout is true and the Editor exists
            if (foldout && editor)
            {
                // Draw the properties of an object in a frame
                GUILayout.BeginVertical(EditorStyles.helpBox);
                editor.OnInspectorGUI();
                GUILayout.EndVertical();
            }
        }
    }

When scrolling (when the field is hidden behind the screen frame), an error occurs: System.ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint The properties are not displayed. Instead, empty space...

There is still a problem with displaying arrays, but for now I want to get rid of at least this error.

I wrapped the error in a try-catch and just hid the properties, but it looks bad.

                // Draw the properties of an object in a frame
                try
                {
                    GUILayout.BeginVertical(EditorStyles.helpBox);
                    editor.OnInspectorGUI();
                    GUILayout.EndVertical();
                }
                catch (System.ArgumentException e)
                {
                    foldout = false;
                }

Solution

  • Your problem is that within a PropertyDrawer you can not use the automatically layouted API from GUILayout or EditorGUILayout but only the absolute Rect API from GUI and EditorGUI always passing in the according start position and dimensions.

    You would need to

    => You can not simply use the default editor to achieve this as it operates in the auto-layout system which can not be used by PropertyDrawers.