EnumField is not compatible with Enum property

Hi. I’m doing a custom editor window and I’m trying to bind an EnumField to an enum property of my custom enum type. But I get the warning:
Field type UnityEditor.UIElements.EnumField is not compatible with Enum property “myEnum”
The enum field works but it isn’t bound so my data object does not update and so when I hit play on the editor, the field loses the information and is set to default. In contrast, the text field works as expected since it retains the correct value.

This is my code.

//DataObject.cs
//Object for binding
public class DataObject : ScriptableObject
{
    public MyEnum myEnum;
    public string myString;

    void OnEnable()
    {
        hideFlags = HideFlags.HideAndDontSave;

        if (myString == null)
            myString = "";
    }
}

//TestWindow.cs
public enum MyEnum
{
   Foo1,
   Foo2,
   Foo3
}

public class TestWindow : EditorWindow
{
   [SerializeField]
   private DataObject dataObject;

   private TextField textField;
   private EnumField enumField;
   
   [MenuItem("Tools/Test Window")]
   private static void ShowEditor()
   {
      TestWindow window = GetWindow<TestWindow>();
      window.titleContent = new GUIContent("Test Window");
   }

   void OnEnable()
   {
      textField = new TextField("Text");
      textField.bindingPath = "myString";
      textField.style.width = StyleKeyword.Auto;
      textField.style.height = 20;
      rootVisualElement.Add(textField);

      enumField = new EnumField("Enum",MyEnum.Foo1);
      enumField.bindingPath = "myEnum";
      enumField.style.width = StyleKeyword.Auto;
      enumField.style.height = 20;
      rootVisualElement.Add(enumField);
      
      
      if (dataObject == null)
      {
         dataObject = CreateInstance<DataObject>();
         dataObject.myString = "default string";
         textField.value = dataObject.myString;
      }
      else
      {
         textField.value = dataObject.myString;
         enumField.value = dataObject.myEnum;
      }
      
      
      var so = new SerializedObject(dataObject);
      //The same thing happens if I try to bind to the field directly instead
      rootVisualElement.Bind(so);
   }
}

I found this post EnumField does not work for custom Enum type
But they solved the issue on UXML. Is this somehow related to my problem, where I’m trying to do the binding by code? What am I missing? Or is this a bug?

If you created EnumField from script, you should call EnumField.Init() for handling custom enum type.

2 Likes

I added the line enumField.Init(MyEnum.Foo1); right after creating the enum field but the result was the same. Same warning.

There seem to be multiple caveats when working with enums on UIElements:

I did some digging on the source code and found a couple of things.

First, here’s the decompiled binding code from my current Unity version (2019.1.0f2)

    private static void DefaultBind<TValue>(VisualElement element, BindingExtensions.SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop, Func<SerializedProperty, TValue> propertyReadFunc, Action<SerializedProperty, TValue> propertyWriteFunc, Func<TValue, SerializedProperty, Func<SerializedProperty, TValue>, bool> valueComparerFunc)
    {
      INotifyValueChanged<TValue> field = element as INotifyValueChanged<TValue>;
      if (field != null)
        BindingExtensions.SerializedObjectBinding<TValue>.CreateBind(field, objWrapper, prop, propertyReadFunc, propertyWriteFunc, valueComparerFunc);
      else
        Debug.LogWarning((object) string.Format("Field type {0} is not compatible with {2} property \"{1}\"", (object) element.GetType().FullName, (object) prop.propertyPath, (object) prop.type));
    }

So, the field != null check is failing meaning that element as INotifyValueChanged is returning null and that’s weird since the element is of type EnumField which inherits from BaseField which implements the interface INotifyValueChanged.

Now here’s the source code straight from github for the same method on Unity version 2019.3.0a3

        private static void DefaultBind<TValue>(VisualElement element, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop,
            Func<SerializedProperty, TValue> propertyReadFunc, Action<SerializedProperty, TValue> propertyWriteFunc,
            Func<TValue, SerializedProperty, Func<SerializedProperty, TValue>, bool> valueComparerFunc)
        {
            var field = element as INotifyValueChanged<TValue>;

            if (element is INotifyValueChanged<string> && typeof(TValue) != typeof(string))
            {
                //One Way Binding here with string conversions

                SerializedObjectStringConversionBinding<TValue>.CreateBind(element as INotifyValueChanged<string>, objWrapper, prop, propertyReadFunc,
                    propertyWriteFunc, valueComparerFunc);
            }
            else if (field != null)
            {
                SerializedObjectBinding<TValue>.CreateBind(field, objWrapper, prop, propertyReadFunc,
                    propertyWriteFunc, valueComparerFunc);
            }
            else
            {
                Debug.LogWarning(string.Format("Field type {0} is not compatible with {2} property \"{1}\"",
                    element.GetType().FullName, prop.propertyPath, prop.type));
            }
        }

As you can see there’s an extra conditional here although it doesn’t seem related to this problem since it is checking for the interface with a string type.

Anybody from Unity that can shed some light on this?

Hello,

Support for binding to EnumField to an enum value was added in 2019.3.

However I cannot see a reason not to do it in 2019.2 and maybe 2019.1. Can you please submit a bug through the bug reporter so you can track that request ?

Thanks.

Sure thing! Thank you very much

Here’s the link to the report:
https://fogbugz.unity3d.com/default.asp?1162585_ud0mqhsh1693b7dd