能否在PropertyDrawer中不使用Begin/EndProperty或PropertyField更新序列化类值?
问题描述
正在将某类的CustomEditor部分功能转换为PropertyDrawer,希望该类始终使用同一编辑器,但此前因转换复杂度较高而搁置。存在一些同时用于运行时和编辑器的函数,希望避免在PropertyDrawer UI中重复实现。
获取对象引用的代码:
var myObject = (MyClass)fieldInfo.GetValue(property.serializedObject.targetObject);
尝试修改的代码示例:
// Size Property // EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(position, sizeProperty); if (EditorGUI.EndChangeCheck()) { var newX = xProperty.intValue; var newY = yProperty.intValue; myObject.SetSize(newX, newY); // <- "myObject" is the object being drawn by the PropertyDrawer }
遇到的问题:即使直接修改对象引用,序列化数据也未更新,似乎Unity会从SerializedProperty重建序列化数据。被调用的函数会操作底层对象的字段(这些字段未使用PropertyField或BeginProperty/EndProperty),希望找到无需重写编辑器UI逻辑的解决办法。
解决方案
核心问题在于Unity的SerializedObject/SerializedProperty是对象序列化数据的缓存副本:直接修改对象实例的字段不会自动同步到缓存,反之缓存的修改也不会自动覆盖对象。要让自定义函数的修改被序列化系统认可,需要手动同步两者的状态。
方法一:同步修改后的对象状态到SerializedProperty
调用共用函数修改对象后,将处理后的字段值同步回对应的SerializedProperty,再提交修改:
EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(position, sizeProperty); if (EditorGUI.EndChangeCheck()) { var newX = xProperty.intValue; var newY = yProperty.intValue; // 记录对象状态,支持Unity编辑器撤销操作 Undo.RecordObject(myObject, "Adjust Size"); // 调用共用函数处理值,修改对象底层字段 myObject.SetSize(newX, newY); // 将处理后的字段值同步回SerializedProperty缓存 xProperty.intValue = myObject.x; yProperty.intValue = myObject.y; // 提交修改,让序列化系统保存最新值 property.serializedObject.ApplyModifiedProperties(); // 标记对象为脏数据,确保修改被写入磁盘(针对MonoBehaviour/ScriptableObject) EditorUtility.SetDirty(myObject); }
方法二:强制从对象刷新SerializedProperty缓存
如果不想手动同步每个字段,可以调用serializedObject.Update()让缓存直接从对象读取最新状态:
EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(position, sizeProperty); if (EditorGUI.EndChangeCheck()) { var newX = xProperty.intValue; var newY = yProperty.intValue; Undo.RecordObject(myObject, "Adjust Size"); myObject.SetSize(newX, newY); // 强制从对象读取最新数据,更新SerializedProperty缓存 property.serializedObject.Update(); }
关键注意事项
- Undo.RecordObject:必须在修改对象前调用,否则编辑器无法记录撤销操作,影响用户体验。
- 字段可序列化性:确保
MyClass中被SetSize修改的字段(如x、y)是Unity可序列化的(即public或标记[SerializeField]),否则SerializedProperty无法访问这些字段。 - 自定义可序列化类:如果
MyClass是嵌套的可序列化类(非MonoBehaviour/ScriptableObject),无需调用EditorUtility.SetDirty,只需确保其所属的父对象被正确标记即可。
内容的提问来源于stack exchange,提问作者hijinxbassist
相关产品推荐
相关产品推荐

