Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

PropertyField ChangeEvent for a Generic property field in 2019.4

Discussion in 'UI Toolkit' started by Tomayopan, May 8, 2022.

  1. Tomayopan

    Tomayopan

    Joined:
    Dec 9, 2020
    Posts:
    11
    Unity Version: 2019.4.26f1

    I have this Serializable struct, the struct itself all it does is store the assemblyQualifiedName of a type, so that i can serialize specific types for a project.

    The SerializableSystemType has a specificly made PropertyDrawer, the property drawer is too large to show properly, but it initializes a "Tree View" of all the available types in the AppDomain, and then sets the SerializableSystemType's assemblyQualifiedName to whatever Type was chosen in the AppDomain.

    I've now tried to make a custom editor for the TypeObject, which itself has a field which's type is SerializableSystemType. below is a handwritten snippet of the general code (Should be enough to get the gist of it)

    Code (CSharp):
    1. namespace MyNamespace
    2. {
    3.     [Serializable]
    4.     public struct SerializableSystemType
    5.     {
    6.         [SerializeField]
    7.         private string assemblyQualifiedName;
    8.  
    9.         public Type type => Type.GetType(assemblyQualifiedName);
    10.     }
    11.  
    12.     public class TypeObject : ScriptableObject
    13.     {
    14.         public SerializableSystemType targetType;
    15.     }
    16.  
    17.     [CustomPropertyDrawer(typeof(SerializableSystemType))]
    18.     public class SerializableSystemTypeDrawer : PropertyDrawer
    19.     {
    20.         //Draw property drawer with IMGUI
    21.     }
    22.  
    23.     [CustomEditor(typeof(TypeObject))]
    24.     public class TypeObjectInspector : Editor
    25.     {
    26.         public override VisualElement CreateInspectorGUI()
    27.         {
    28.             PropertyField pField = new PropertyField();
    29.             pField.bindingPath = "targetType";
    30.             pField.RegisterCallback<ChangeEvent<string>>(OnTypeSet);
    31.             return pField;
    32.         }
    33.  
    34.         private void OnTypeSet(ChangeEvent<string> evt)
    35.         {
    36.             //Do stuff;
    37.         }
    38.     }
    39. }
    The issue i'm having is that OnTypeSet is never getting called when the property field's value changes. Digging through some more i noticed that the targetType's serializeablePropertyType is "Generic". according to the documentation it means that targetType's propertyType shopuld be SerializableSystemType.
    However, changing the ChangeEvent to be
    pField.RegisterCallback<ChangeEvent<SerializableSystemType>>(OnTypeSet);
    makes no difference, as the event still does not fire.

    Keep in mind, this is unity 2019.4, this version does not have the SerializablePropertyChangeEvent, which would be a solution to this issue, alas, it isnt a thing in 2019.4 as far as i know.
     
  2. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    The
    ChangeEvent
    is actually fired by the fields that are bound directly the data; those are usually fields that inherit from
    BindableElement
    , or at least implement
    INotifyValueChange
    .
    PropertyField
    is not one of those so, usually, its Change Events are fired by nested basic fields within it. For
    pField
    to fire a
    ChangeEvent<string>
    , your custom drawer would have to contain a
    TextField
    or something similar; something that observes the actual string.

    It's hard to help you without seeing the code for the drawer, as the elements that you create in your drawer are the ones that should fire the ChangeEvent. There aren't a lot of options in 2019 for tracking values. I created an utility class some time ago that could help you circumvent the problem; you'd need to add an extra element besides your
    pField
    that would be bound to
    "targetType.assemblyQualifiedName"
    to track its value.
     
  3. Tomayopan

    Tomayopan

    Joined:
    Dec 9, 2020
    Posts:
    11
    yeah, its quite unfortunate. In the end i made something extremely hacky which was just make a LabelField and set the binding Path to targetType.assemblyQualifiedName, and afterwards registering a change event there.

    It is extremely hacky, and honestly i'm suprised it works. i think something similar could be done for other cases but its certainly not a good solution
     
  4. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    You're in a very old Unity version with an API that got frozen about three years ago. I think it's not a bad solution, because you don't have a lot of options in 2019. Specifically for this issue, the best solution would be to use a newer version. I realize that you probably can't, but if you were able upgrade to 2021, you wouldn't even need to listen to any event that comes from any other field, you could just use TrackPropertyValue. Otherwise, I'd say what you are doing is a good solution given the circumstances.
     
    Last edited: May 14, 2022