- Home /
PropertyDrawer.fieldInfo returns array instead of eleme
Hi, I have written a PropertyDrawer for an custom class. For this class I have several Defaults (like Vector3 has up, right,..) The PropertyDrawer shows a Popuplist of all those defaults.
object targetObj = fieldInfo.GetValue(prop.serializedObject.targetObject);
MyClass target = targetObj as MyClass;
//find index in defaults list
//show popup
//if changed -> apply
target = MyClass.GetDefault(selectedIndex);
This works like a charm if there is a single MyClass Object. When there is an array of MyClass the targetObj becomes an array too.
[SerializeField] MyClass test = new MyClass(); //works
[SerializeField] MyClass[] test2; //Elements are not initialized when size is set in inspector
[SerializeField] MyClass[] test3 = { //only access to whole array
new MyClass(),
new MyClass(),
new MyClass()
};
So why is that? Is there a way to determine the actual Element's index? (targetObj can be cast to MyClass[] ) Or is there a simpler way I don't know of?
I have done some further tests. Could fetch the actual array index by dismantling the propertypath like this:
object targetObj = fieldInfo.GetValue(prop.serializedObject.targetObject);
$$anonymous$$yClass target = null;
int targetArrayIndex = -1;
$$anonymous$$yClass[] targetArray = null;
if (targetObj.GetType().ToString() == "$$anonymous$$yClass[]") {
targetArrayIndex = System.Convert.ToInt32(prop.propertyPath.Substring(prop.propertyPath.IndexOf("[")+1).Replace("]",""));
targetArray = targetObj as $$anonymous$$yClass[];
if (targetArrayIndex < targetArray.Length) {
target = targetArray[targetArrayIndex];
} else return; //array size changed, elements will be initialized by inspector
}
//find selectedIndex in Defaults ..
//show value popup and apply changes
int newSelectedIndex = EditorGUI.Popup(pos, selectedIndex, $$anonymous$$yClass.DefaultsStr);
if (newSelectedIndex != selectedIndex) {
if (targetArrayIndex == -1)
target = $$anonymous$$yClass.GetDefault($$anonymous$$yClass.DefaultsStr[newSelectedIndex]);
else
targetArray[targetArrayIndex] = $$anonymous$$yClass.GetDefault($$anonymous$$yClass.DefaultsStr[newSelectedIndex ]);
prop.serializedObject.Apply$$anonymous$$odifiedProperties();
}
This does show existing values and applies change correctly.
Unfortunately all elements will be replaced with the last element when the array's size is altered in inspector.
So why is there no target property like editor has for propertydrawer?
Answer by EvanTreborn · May 30, 2015 at 02:34 PM
I found a workaround for it.
I added an ID attribute to MyClass and wrote a serializeable wraperclass which holds the private object and the [SerializeField] int ID. The wraperclass has a getter which checks if the object is set and the object.ID is equal to the stored ID if not it will fetch the object from the defaults array by the stored ID.
I wrote a property drawer for the warperclass which only sets the ID using a popuplist of all the defined defaults. I can even add new defaults at runtime to the static defaults array. This has to be done before any other object tries to read a MyClassWrapper object though.
Answer by llamagod · Sep 07, 2016 at 12:48 PM
The reason why the array fieldInfo is provided is because array elements aren't fields so they have no FieldInfo. You can set the elements by getting the value of the array and then setting the element as you have done. I would probably have gotten the index using Regex instead, but whatever floats your boat.
Your answer
