Search Unity

why PropertyDrawer Call OnGUI before array add new element?

Discussion in 'Immediate Mode GUI (IMGUI)' started by bbsuuo, Jan 21, 2020.

  1. bbsuuo

    bbsuuo

    Joined:
    Jul 21, 2016
    Posts:
    16
    i want Serializable some class without MonoBehaviour, but get some program

    some class it's fire ,but some class have error:
    System.InvalidOperationException: Operation is not valid due to the current state of the object


    and i check my scripts, the program is constructed element before Ongui,so array count is Zero,

    Isn't the array always constructed before OnGUI

    i try Debug.Log((property.serializedObject.targetObject as MachineBehaviour).handlers.Count);

    when i add element and some class value will one , some class value is zero



    Code (CSharp):
    1. using StateMachine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Reflection;
    6. using UnityEngine;
    7.  
    8. [System.Serializable]
    9. public class StatePropertyHandler
    10. {
    11.     public string stateType;
    12.     public List<StateFieldHandler> stateFieldHandler = new List<StateFieldHandler>();
    13.  
    14.  
    15.  
    16.     public void Serializable(Type stateType) {
    17.         if (stateType  == null || this.stateType == stateType.Name) return;
    18.         this.stateType = stateType.Name;
    19.         stateFieldHandler = new List<StateFieldHandler>();
    20.         var fields = StatePropertyUtility.GetAttributeField(stateType);
    21.  
    22.         for (int i = 0; i < fields.Count; i++)
    23.         {
    24.             StateFieldHandler handler = new StateFieldHandler(fields[i]);
    25.             stateFieldHandler.Add(handler);
    26.         }
    27.  
    28.         // stateFieldHandler = new List<StateFieldHandler>();
    29.         //重新赋值stateFieldHandler
    30.     }
    31.  
    32.  
    33.  
    34.  
    35.  
    36.     [NonSerialized]
    37.     public MachineBehaviour machine;
    38.     public void DeSerializable(State target) {
    39.         machine = target.machine as MachineBehaviour;
    40.  
    41.         //赋值给state
    42.         for (int i = 0; i < stateFieldHandler.Count; i++) {
    43.             var handler = stateFieldHandler[i];
    44.             handler.DeSerializableState(target);
    45.         }
    46.  
    47.     }
    48.  
    49. }
    50.  
    51. [System.Serializable]
    52. public class StateFieldHandler
    53. {
    54.     public string fieldName;
    55.     public string fieldType;
    56.    
    57.  
    58.     [NonSerialized]
    59.     private FieldInfo targetField;
    60.    public FieldInfo TargetField { get {
    61.             if (targetField == null) {
    62.                 targetField = GetTargetType(fieldType);
    63.             }
    64.             return targetField;
    65.         }    
    66.     }
    67.  
    68.     public bool boolValue;
    69.     public float floatValue;
    70.     public int intValue;
    71.     public string stringValue;
    72.     public Vector3 vector3Value;
    73.     public Color colorValue;
    74.     public AnimationCurve animationCurveValue;
    75.     public Transform transformValue;
    76.  
    77.  
    78.     public FieldInfo GetTargetType(string orginType) {
    79.      
    80.         var thisFields =  this.GetType().GetFields(BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    81.         for (int i = 0; i < thisFields.Length; i++) {
    82.             if (thisFields[i].Name == "fieldName" || thisFields[i].Name == "fieldType") {
    83.                 continue;
    84.             }
    85.  
    86.             if (thisFields[i].FieldType.Name == orginType) {
    87.                 return thisFields[i];
    88.             }
    89.         }
    90.         return null;
    91.     }
    92.  
    93.     public StateFieldHandler(FieldInfoHandler fieldInfoHandler) {
    94.         SetDefaultValue(fieldInfoHandler);
    95.     }
    96.  
    97.     protected void SetDefaultValue(FieldInfoHandler fieldInfoHandler) {
    98.      
    99.      
    100.         this.fieldName = fieldInfoHandler.info.Name;
    101.         this.fieldType = fieldInfoHandler.info.FieldType.Name;
    102.         FieldInfo targetField = GetTargetType(fieldType);
    103.         if (targetField == null) {
    104.             Debug.LogError("Not Support OrginType :" + fieldType);
    105.             return;
    106.         }
    107.         targetField.SetValue(this,fieldInfoHandler.defaultValue);
    108.     }
    109.  
    110.  
    111.  
    112.     protected object GetValue() {      
    113.         return TargetField.GetValue(this);
    114.     }
    115.  
    116.     public FieldInfo GetStateField(State target) {
    117.         var infos =  target.GetType().GetFields(BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    118.         for (int i = 0; i < infos.Length; i++) {
    119.             if (infos[i].Name == fieldName) {
    120.                 return infos[i];
    121.             }
    122.         }
    123.         return null;
    124.     }
    125.  
    126.     public void DeSerializableState(State target) {
    127.         if (TargetField == null) {
    128.             Debug.LogError("Not Support OrginType :" + fieldType);
    129.             return;
    130.         }
    131.         object value = GetValue();
    132.         if (value != null) {
    133.             FieldInfo stateField = GetStateField(target);
    134.             if (stateField != null)
    135.             {
    136.                 stateField.SetValue(target, value);
    137.             }
    138.             else {
    139.                 Debug.LogError("not find field from state:" + fieldName+"|"+fieldType);
    140.             }
    141.             //TargetField.SetValue(target,value);
    142.             //从 Target里找同名的Field
    143.  
    144.         }
    145.     }
    146. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System;
    6. using StateMachine;
    7. using UnityEditor.SceneManagement;
    8. using System.Linq;
    9. using System.Reflection;
    10.  
    11. [CustomPropertyDrawer(typeof(StatePropertyHandler))]
    12. public class StatePropertyHandlerEditor : PropertyDrawer {
    13.     //public List<StatePropertyHandlerDraw> drawers = new List<StatePropertyHandlerDraw>();
    14.     public Dictionary<string, StatePropertyHandlerDraw> drawers = new Dictionary<string, StatePropertyHandlerDraw>();
    15.  
    16.     public static  UnityEngine.Object targetObject;
    17.  
    18.     public StatePropertyHandlerDraw Register(string fullPath, SerializedProperty property) {
    19.         StatePropertyHandlerDraw drawer = new StatePropertyHandlerDraw(property);
    20.         drawers.Add(fullPath, drawer);
    21.         return drawer;
    22.     }
    23.  
    24.  
    25.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    26.     {
    27.         var drawer = drawers.TryGet(property.serializedObject.targetObject.GetInstanceID() + property.propertyPath);
    28.         if (drawer == null) {
    29.             //drawer = Register(property.propertyPath,property);
    30.             return 15;
    31.         }
    32.        
    33.         return drawer.GetHeight();
    34.  
    35.     }
    36.  
    37.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    38.     {
    39.   [I][B][U]      Debug.Log((property.serializedObject.targetObject as MachineBehaviour).handlers.Count);[/U][/B][/I]
    40.         var drawer = drawers.TryGet(property.serializedObject.targetObject.GetInstanceID() + property.propertyPath);
    41.         if (drawer == null)
    42.         {
    43.             drawer = Register(property.serializedObject.targetObject.GetInstanceID() + property.propertyPath, property);
    44.         }
    45.         else
    46.         {
    47.             drawer.EditorOnGUI(position, property, label);
    48.         }
    49.     }
    50.  
    51.  
    52.  
    53.  
    54.  
    55.  
    56. }
    57.  
    58.  
    59. public class StatePropertyHandlerDraw {
    60.  
    61.     private static Type[] allTypes;
    62.     private static string[] stateContent;
    63.  
    64.  
    65.     private static GUIStyle redFont;
    66.     private static GUIStyle greenFont;
    67.  
    68.     public string propertyRealPath;
    69.  
    70.     public StatePropertyHandler target;
    71.     private int selectStateIndex;
    72.     private int lastSelelctStateIndex;
    73.  
    74.  
    75.     SerializedProperty property;
    76.    
    77.  
    78.     float height;
    79.  
    80.     bool enable = true;
    81.     public StatePropertyHandlerDraw(SerializedProperty property) {
    82.  
    83.         Init(property);
    84.     }
    85.  
    86.     private bool init = false;
    87.     public void Init(SerializedProperty property) {
    88.         try
    89.         {
    90.             target = GetParent(property) as StatePropertyHandler;
    91.         }
    92.         catch (Exception e) {
    93.             Debug.LogError(e);
    94.         }
    95.         if (allTypes == null || stateContent == null)
    96.         {
    97.             allTypes = StatePropertyUtility.GetExecutingAssemblyTypesName<State>();
    98.             stateContent = new string[allTypes.Length];
    99.         }
    100.         if (target == null || allTypes == null) return;
    101.  
    102.  
    103.         for (int i = 0; i < allTypes.Length; i++)
    104.         {
    105.             string typeName = allTypes[i].Name;
    106.             stateContent[i] = allTypes[i].Name;
    107.             if (typeName == target.stateType)
    108.             {
    109.                 lastSelelctStateIndex = selectStateIndex = i;
    110.             }
    111.         }
    112.         Undo.undoRedoPerformed += UndoRedoCallBack;
    113.         SetHeight();
    114.        
    115.     }
    116.  
    117.  
    118.     public void UndoRedoCallBack()
    119.     {
    120.  
    121.  
    122.  
    123.         if (!Application.isPlaying)
    124.         {
    125.             if (allTypes[selectStateIndex].Name != target.stateType)
    126.             {
    127.                 var currentIndex = 0;
    128.                 for (int i = 0; i < allTypes.Length; i++)
    129.                 {
    130.                     string typeName = allTypes[i].Name;
    131.                     stateContent[i] = allTypes[i].Name;
    132.                     if (typeName == target.stateType)
    133.                     {
    134.                         currentIndex = i;
    135.                     }
    136.                 }
    137.  
    138.                 if (selectStateIndex != currentIndex)
    139.                 {
    140.                     selectStateIndex = lastSelelctStateIndex = currentIndex;
    141.                 }
    142.                 SetHeight();
    143.             }
    144.         }
    145.  
    146.     }
    147.  
    148.     public void EditorOnGUI(Rect position, SerializedProperty property, GUIContent label) {
    149.         if (target == null)
    150.         {
    151.             Init(property);
    152.             EditorGUI.LabelField(position, "UKNOW ERROR");
    153.             return;
    154.         }
    155.         GUI.Box(position, "");
    156.         EditorGUI.BeginChangeCheck();
    157.         Rect baseRect = position; baseRect.height = EditorGUIUtility.singleLineHeight;
    158.         baseRect.y += 5;
    159.  
    160.  
    161.         bool notHaveState = target == null || target.stateFieldHandler.Count == 0;
    162.        
    163.  
    164.         enable = EditorGUI.ToggleLeft(baseRect, target.stateType, enable);
    165.  
    166.         if (enable)
    167.         {
    168.            
    169.  
    170.             EditorGUI.BeginProperty(position, label, property);
    171.    
    172.  
    173.             baseRect.y += 20;
    174.             Undo.RecordObject(property.serializedObject.targetObject, "Change State");
    175.  
    176.  
    177.            
    178.             selectStateIndex = EditorGUI.Popup(baseRect, target.stateType, selectStateIndex, stateContent);
    179.             if (lastSelelctStateIndex != selectStateIndex)
    180.             {
    181.                 target.Serializable(allTypes[selectStateIndex]);
    182.                 SetHeight();
    183.                 //DoSomeThing
    184.                 lastSelelctStateIndex = selectStateIndex;
    185.  
    186.             }
    187.  
    188.  
    189.             if (notHaveState)
    190.             {
    191.                 position.y += 5;
    192.                 baseRect.y += EditorGUIUtility.singleLineHeight;
    193.                 EditorGUI.LabelField(baseRect, "Not Support State Type Or State Not Have Attribute!, Please ReSelect");
    194.                 return;
    195.             }
    196.             else
    197.             {
    198.  
    199.  
    200.                 for (int i = 0; i < target.stateFieldHandler.Count; i++)
    201.                 {
    202.                     Rect singeRect = baseRect;
    203.                     singeRect.y = baseRect.y + (20f * (i + 1));
    204.                     DrawSingleField(singeRect, target.stateFieldHandler[i], property);
    205.                 }
    206.  
    207.  
    208.  
    209.  
    210.             }
    211.  
    212.    
    213.      
    214.         EditorGUI.EndProperty();
    215.         }
    216.  
    217.         if (EditorGUI.EndChangeCheck())
    218.         {
    219.             SetHeight();
    220.             property.serializedObject.ApplyModifiedProperties();
    221.             EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    222.  
    223.         }
    224.     }
    225.  
    226.  
    227.  
    228.  
    229.  
    230.  
    231.     public void DrawSingleField(Rect rect, StateFieldHandler handler, SerializedProperty property)
    232.     {
    233.         //GUI.Box(rect, "",GUI.skin.textField);
    234.  
    235.         if (handler.TargetField == null)
    236.         {
    237.             EditorGUI.LabelField(rect, "Not Support this Type:" + handler.fieldType);
    238.             return;
    239.         }
    240.  
    241.         DrawFieldByType(rect, handler, property);
    242.     }
    243.  
    244.     public void DrawFieldByType(Rect rect, StateFieldHandler handler, SerializedProperty property)
    245.     {
    246.         if (handler.TargetField == null) {
    247.             EditorGUI.LabelField(rect, "Not Support this Type:" + handler.fieldType);
    248.         }
    249.         Type fieldType = handler.TargetField.FieldType;
    250.         GUIContent content = EditorGUIUtility.ObjectContent(null, fieldType);
    251.         Undo.RecordObject(property.serializedObject.targetObject, "Field Change" + handler.TargetField);
    252.         //EditorGUI.ObjectField(rect,content,null,fieldType,false);
    253.         content.text = handler.fieldName;
    254.         if (fieldType == typeof(string))
    255.         {
    256.             handler.stringValue = EditorGUI.TextField(rect, content, handler.stringValue);
    257.         }
    258.         else if (fieldType == typeof(int))
    259.         {
    260.             handler.intValue = EditorGUI.IntField(rect, content, handler.intValue);
    261.         }
    262.         else if (fieldType == typeof(bool))
    263.         {
    264.             handler.boolValue = EditorGUI.Toggle(rect, content, handler.boolValue);
    265.         }
    266.         else if (fieldType == typeof(float))
    267.         {
    268.             handler.floatValue = EditorGUI.FloatField(rect, content, handler.floatValue);
    269.         }
    270.         else if (fieldType == typeof(Vector3))
    271.         {
    272.             handler.vector3Value = EditorGUI.Vector3Field(rect, content, handler.vector3Value);
    273.         }
    274.         else if (fieldType == typeof(Color))
    275.         {
    276.             handler.colorValue = EditorGUI.ColorField(rect, content, handler.colorValue);
    277.         }
    278.         else if (fieldType == typeof(AnimationCurve))
    279.         {
    280.             if (handler.animationCurveValue == null) { handler.animationCurveValue = AnimationCurve.Linear(1, 1, 1, 1); }
    281.             handler.animationCurveValue = EditorGUI.CurveField(rect, content, handler.animationCurveValue);
    282.         }
    283.         else if (fieldType == typeof(Transform))
    284.         {
    285.             handler.transformValue = EditorGUI.ObjectField(rect, content
    286.                 , handler.transformValue, typeof(Transform), true) as Transform;
    287.         }
    288.         else
    289.         {
    290.             EditorGUI.LabelField(rect, "Not Support this Type:" + handler.fieldType);
    291.         }
    292.  
    293.  
    294.  
    295.     }
    296.  
    297.  
    298.     private void SetHeight()
    299.     {
    300.         int count = target == null ? 15 : target.stateFieldHandler.Count;
    301.  
    302.  
    303.         height = 60 + count * 20;
    304.      
    305.     }
    306.  
    307.     public float GetHeight()
    308.     {
    309.         if (target == null) {
    310.             return 15;
    311.         }
    312.         if (height == 0) {
    313.             SetHeight();
    314.         }
    315.  
    316.         if (!enable)
    317.         {
    318.             return 45;
    319.         }
    320.         return height;
    321.     }
    322.  
    323.  
    324.  
    325.  
    326.     public object GetParent(SerializedProperty prop)
    327.     {
    328.  
    329.         var path = prop.propertyPath.Replace(".Array.data[", "[");
    330.         object obj = prop.serializedObject.targetObject;
    331.         var elements = path.Split('.');
    332.         //foreach (var element in elements.Take(elements.Length - 1))
    333.         for (int i = 0; i < elements.Length; i++)
    334.         {
    335.             var element = elements[i];
    336.          
    337.             if (element.Contains("["))
    338.             {
    339.                 var elementName = element.Substring(0, element.IndexOf("["));
    340.                 var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
    341.              
    342.                 obj = GetValue(obj, elementName, index);
    343.             }
    344.             else
    345.             {
    346.                 obj = GetValue(obj, element);
    347.             }
    348.         }
    349.         return obj;
    350.     }
    351.  
    352.     public object GetValue(object source, string name)
    353.     {
    354.         if (source == null)
    355.             return null;
    356.         var type = source.GetType();
    357.         var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    358.         if (f == null)
    359.         {
    360.             var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
    361.             if (p == null)
    362.                 return null;
    363.             return p.GetValue(source, null);
    364.         }
    365.         return f.GetValue(source);
    366.     }
    367.  
    368.     public object GetValue(object source, string name, int index)
    369.     {
    370.        
    371.         var enumerable = GetValue(source, name) as IEnumerable;
    372.         var enm = enumerable.GetEnumerator();//as IList<StateFieldHandler>;
    373.                          
    374.         while (index-- >= 0)
    375.         {
    376.        
    377.           bool next=   enm.MoveNext();  
    378.         }
    379.  
    380.        
    381.         return enm.Current;
    382.     }
    383.  
    384. }
    385.  
    386.  
     

    Attached Files:

  2. bbsuuo

    bbsuuo

    Joined:
    Jul 21, 2016
    Posts:
    16
    i wait a frame when OnGUI ,it's work , but i still feel this's strange error