Say I got myStringField in my serialized object, but I don’t want to just use PropertyField where overrides (bolded text + blue bar + right click menu) is supported, and instead I want to display a popup with choices. It works but without override support. What is an equivalent of the old BeginProperty code in the old way?
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
var myStringField = serializedObject.FindProperty("myStringField");
var list = new string[] { "A", "B", "C" }.ToList();
var pf = new PopupField<string>(list, list[0]);
pf.RegisterValueChangedCallback(ev =>
{
myStringField.stringValue = ev.newValue;
serializedObject.ApplyModifiedProperties();
});
root.Add(pf);
return root;
}
(Also, how to handle Cmd+Z undo event? When I press undo while the popup is displaying, the underlying myStringField undo, but the popup is not refreshed yet)
First off, you can bind any individual field to a SerializedProperty, it doesn’t have to be a PropertyField. Any field can have its bindingPath set.
Now, for the string->choices conversion, what you could try is to bind a hidden TextField to your myStringField. Then, you register for change events on this hidden TextField (height 0?). On every change, you compare the new value against your list of options and change your actual visible PopupField to reflect the new value.
Same for the reverse. When the user changes the PopupField, you can set the string value on your TextField which will then also change the SerializedObject state.
From this point on, undo/redo should work as expected without extra work for you to do. When you trigger an Undo, the underlying value of the object will change, which will trigger your TextField to change, which will trigger your PopupField to change.
@uDamian - reading this helped with my current similar problem: changing the value of a FloatField and then hitting ctrl-Z had no effect, despite me using SerializedProperty and a PropertyField.
Given your advice above, I realised: maybe Undo is working, it’s just that UIToolkit is failing to render the change. Lo and behold: yes! When I hit ctrl-z, the underlying data is changed. But UIToolkit is wrong, displays wrong values.
I’m not using anything fancy like a PopupField. I’m using a plain old FloatField. Is there any obvious reason this might be going wrong?
Situation:
Parent class:
public class MyMB : MonoBehaviour
{
public MyData myData;
}
Parent Editor:
[CustomEditor(typeof(MyMB))] public class MyEditor : Editor
Basic data class:
[Serializable] public class MyData { public float value; }
Basic data PropertyDrawer:
[CustomPropertyDrawer(typeof(MyData))]
public class PropertyDrawerForMyData : PropertyDrawer
PropertyField in the main Editor to render all of it:
(inside MyEditor):
var f = new PropertyField(serializedObject.FindProperty( “myData” )
Things I’ve checked:
Is the property drawer a UIToolkit drawer instead of an IMGUI drawer? (yes)
Does the FloatField have a .bindingPath set to the exact name of the SerializedProperty that’s being changed? (yes - it’s the same string that’s being passed to “(SerializedProperty.FindRelative( [string here] )”)
Does the value update in a Debug-mode Inspector? (yes)
Does the value update with Ctrl-Z in a Debug-mode Inspector? (yes)
Am I calling ApplyModifiedProperties when the FloatField changes value? (yes)
This seems to precisely follow the instructions for PropertyField. Yet something is missing ?
AAAARRGGH! Finally figured it out. Undocumented but I remember you mentioning stuff about how Bind() is automatically called in a lot of places, and when it isn’t called has to be called manually.
The missing line is this:
numberField.Bind( property.serializedObject );
…adding that made it all work. I guess ‘custom property drawers’ are one of those places where manual calls to .Bind() are necessary :).