VisualElement PropertyDrawers invalid cached memory when used inside a list

Hello,

I’m writing a custom PropertyDrawer in VisualElement using OnCreatePropertyGUI(). Inside this drawer I’m caching some data and registering to a click event.

The issue is that when the PropertyDrawer is used inside a list, it sometimes retains invalid data.

Here is a example :

[CreateAssetMenu(fileName = "Item", menuName = "TEST/Create Item")]
public class CustomDataItem : ScriptableObject
{
    public string debugText;
} 

[CustomPropertyDrawer(typeof(CustomDataItem))]
public class CustomDataItem_PropertyDrawer : PropertyDrawer
{
    private SerializedProperty cachedProperty;
    private string cachedGuid;

    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        // Cached some data
        cachedProperty = property;
        cachedGuid = GUID.Generate().ToString().Substring(0, 5);
        
        // Create and bind the field.
        PropertyField field = new PropertyField(cachedProperty);
        field.RegisterCallback<ClickEvent>(OnItemClicked);

        // Serialize data into the field to retrieve it later.
        field.userData = $"{property.propertyPath}#{cachedGuid}";

        return field;
    }

    private void OnItemClicked(ClickEvent click)
    {
        VisualElement sourceField = click.currentTarget as VisualElement;
        string fieldRawData = (string)(sourceField.userData);
        string[] fieldData = fieldRawData.Split('#');

        string debugText = $"Cached Data: <color=magenta>{cachedProperty.propertyPath} ({cachedGuid})</color>; " +
                           $"Field Data: <color=magenta>{fieldData[0]} ({fieldData[1]})</color>";

        if (cachedProperty.propertyPath != fieldData[0])
            Debug.LogError(debugText);
        else
            Debug.Log(debugText);

    }
}

[CreateAssetMenu(fileName = "TestData",menuName = "TEST/Create Test Data")]
public class TestData : ScriptableObject
{
    public CustomDataItem singleItem;

    public CustomDataItem[] itemsCollections;
}

When clicking on a CustomDataItem stored into itemsCollection we can see that the cached data mismatch it’s visual representation. Field Element 0 can point to itemsCollections[2] etc…
This behaviour appears to be random and starts after adding or moving items in the list.

A video and all scripts can be found in the .unitypacakge attached.
VisualElement_PropertyDrawer_List.unitypackage (276.5 KB)

Is this a bug or am I missing something ?

Thanks.

Property drawers are recycled so they need to be stateless.

If you need to cache values, write a custom visual element and do so inside that.

In an example I wrote for a [SerializeReference] drawer, you can see how I cache the SerializedProperty in the custom visual element itself: abstract SkillList that can be edited in Inspector - #15 by spiney199

1 Like

Alright, that confirms what I was thinking… Strange nothing mentions this in the official documentation.
Thanks !

You’re right, the documentation doesn’t note that. I just reported that page so hopefully this gets added.