I am writing a property attribute to render C# class property (with setter and getter), by using reflection and serializing the backing field.
The inspector correctly calls the getter and setter, and undo also works properly. However when I make this object into a prefab, change the instance value and click apply, the prefab does not change accordingly. Prefab “Revert” and “Select” work fine. Any help would be very much appreciated. Thanks in advance.
The logic is simple - Pass in the C# Property Name through the attribute, and use reflection in PropertyDrawer to get the corresponding getter and setter by reflection. The following is my attempt (it uses a Transform type, but whatever type will do):
@MyClass.cs
public class MyClass: MonoBehaviour {
[ExposeProperty("TargetTransform"), SerializeField]
private Transform _mTarTransfrom;
public Transform TargetTransform {
get { return _mTarTransfrom; }
set { _mTarTransfrom = value; }
}
}
@ExposePropertyAttribute.cs
public class ExposePropertyAttribute : PropertyAttribute {
public string PropertyName;
public ExposePropertyAttribute(string propName) { PropertyName = propName; }
}
@ExposePropertyDrawer.cs
[CustomPropertyDrawer(typeof(ExposePropertyAttribute))]
public class ExposePropertyDrawer: PropertyDrawer {
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
var a = attribute as ExposePropertyAttribute;
// Get the C# property name
var obj = property.serializedObject.targetObject;
var info = obj.GetType().GetProperty(a.PropertyName);
var t = info.PropertyType;
// Use Reflection to retrieve the accessible Getter/Setter
MethodInfo g = default(MethodInfo), s = default(MethodInfo);
if (info.CanRead) { g = info.GetGetMethod(); }
if (info.CanWrite) { s = info.GetSetMethod(); }
Object oldValue = null;
if (g != null) { oldValue = g.Invoke(obj, null) as Object; }
// draw the field with the getter
// if we don't have a setter, gray out the field
GUI.enabled = (s != null);
var newValue = EditorGUI.ObjectField(position, a.Label, oldValue, t, true);
GUI.enabled = true;
// if the value has changed, perform the change
if (s != null && oldValue != newValue) {
Undo.RecordObject(obj, a.PropertyName);
s.Invoke(obj, new[] { newValue });
}
}
}