Hello hello!
I hope you’re doing alright. Basically, I’m facing an issue since some weeks now, and tried a lot of alternatives to what I want to do, but nothing helped me really much.
Here, I got a basic Interface:
public interface ITestingAttribute { }
And then, I this first custom Attribute:
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public class IFirstTesting : PropertyAttribute, ITestingAttribute { }
And finally, this one:
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public class ISecondTesting : PropertyAttribute, ITestingAttribute { }
After that, I made a CustomPropertyDrawer to do some testing. Here it is:
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
[CustomPropertyDrawer(typeof(ITestingAttribute), true)]
public class ITestingDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
// Tracking every Attribute of the property
TrackEveryAttribute(property);
// Creating the container to return
VisualElement propertyContainer = new()
{
name = property.name + "_Container"
};
// Creating the PropertyField of the property
PropertyField propertyField = new(property)
{
name = $"{property.name}_PropertyField"
};
// Adding the PropertyField to the container and returning it
propertyContainer.Add(propertyField);
return propertyContainer;
}
private void TrackEveryAttribute(SerializedProperty property)
{
// Get every custom attributes of the property field
string[] attributes = fieldInfo.GetCustomAttributes(typeof(ITestingAttribute), true).Select(attr => attr.GetType().Name).ToArray();
// Log each Attribute
if (attributes.Contains(nameof(IFirstTesting)))
{
Debug.Log($"The property '{property.name}' contains the Attribute {nameof(IFirstTesting)}");
}
if (attributes.Contains(nameof(ISecondTesting)))
{
Debug.Log($"The property '{property.name}' contains the Attribute {nameof(ISecondTesting)}");
}
}
}
Bascially, when I use my two Attributes on a property, like that:
using UnityEngine;
public class FirstTester : MonoBehaviour
{
[IFirstTesting]
[ISecondTesting]
public string testString;
}
‘CreatePropertyGUI’ is called two times. Now here is the twist:
- When I return ‘default’, ‘null’, or ‘new()’, then ‘CreatePropertyGUI’ is called only one time.
- What I’m trying to do, is to draw a property, according to its Attributes, in a single Drawer, because I have to do some different settings when 2 Attributes or more of the same Interface are added to it.
When I draw the property with this code, I obtain this in the UI Toolkit Debugger:
Meaning that:
- The PropertyField is not really replaced by my container, but got it as its child,and when CreatePropertyGUI is called a second time, the PropertField that is overrided is not the first one (PropertyField:testString), but the previous one that I made (testString_PropertyField).
For me, it’s a problem because it keeps adding children to the main element based on the amount of Attributes I add to my property, instead of replacing the previous ones.
Also, I tried to add inside a static Dictionary the first returned container, in the hope of returning it again if CreatePropertyGUI is called again, but it created a StackOverflow error.
So, how can I handle multiple Attributes with a single drawer, without having CreatePropertyGUI called more than one time? And if it has to be called more than one time without any other alternative, then how can I avoid creating more and more children every time? Can I just find a way to return what I already created?
.
I’m sorry for the very long message, if anyone can help, I’d be very happy about it. Take care,
Ilario
.
EDIT: I added the scripts I’m using for you if you need them.
Drawer-Testing-Ilario.unitypackage (1.9 KB)