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

Editor serializedObject does not apply updated properties properly

Discussion in 'Scripting' started by rubcc95, Apr 25, 2021.

Thread Status:
Not open for further replies.
  1. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    There's a minimal example.

    Code (CSharp):
    1.     public class TestBehaviour : MonoBehaviour
    2.     {
    3.         [SerializeField] int _value = 0;
    4.     }
    5.  
    6.     [CustomEditor(typeof(TestBehaviour))]
    7.     public class TestEditor : Editor
    8.     {
    9.         SerializedProperty _serializedValue;
    10.  
    11.         private void OnEnable()
    12.         {
    13.             _serializedValue = serializedObject.FindProperty("_value");
    14.         }
    15.  
    16.         public override void OnInspectorGUI()
    17.         {
    18.             base.OnInspectorGUI();
    19.  
    20.             if (GUILayout.Button("Add"))
    21.             {
    22.                 Debug.Log("Add Pressed");
    23.                 _serializedValue.intValue++;
    24.             }
    25.  
    26.             if (Event.current.isKey)
    27.             {
    28.                 Debug.Log("Key Pressed");
    29.                 _serializedValue.intValue++;
    30.             }
    31.  
    32.             if (Event.current.type == EventType.DragExited)
    33.             {
    34.                 Debug.Log("Drag Exited");
    35.                 _serializedValue.intValue++;
    36.             }
    37.  
    38.             serializedObject.ApplyModifiedProperties();
    39.         }
    40.     }
    You can try it yourself. If you press the add button at the inspector, "Add Pressed" is printed and value field is increased.
    If you press any key while hovering the inspector, "Key Pressed" is printed and value field is also increased.
    If you drag any of your assets to the inspector "Drag Exited" is printed BUT value field is NOT increased.

    I'm missing something? Why it happens...
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    This will read the value then increase it. It doesn't do it in-situ. This is how C# works.

    If you read a value from a property then change that value, it isn't somehow linked from where you read it.

    Try:
    Code (CSharp):
    1. var someValue = _serializedValue.intValue;
    2. someValue++;
    3.  _serializedValue.intValue = someValue;
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    TBH I've not actually checked if this is a property or field. If it's a field you should be okay. I guess I better check to make sure I'm not talking nonsense!
     
  4. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Thanks you for the fast response MelvMay, but im just changing the value directly from the SerializedProperty and not from any copy. In fact, it works perfectly in the case of the button and the key event. It only fails at DragEvent comparison.

    This one is the basically the same example, but making the changes at a Custom Editor Window.
    If you drag some asset to the window while still having inspector in view, you can see how the values changes at the new EditorWindow, but not at the inspector. If you press the button or some key, both EditorWindow and inspector values are updated.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. namespace Test
    5. {
    6.     public class TestBehaviour : MonoBehaviour
    7.     {
    8.         [SerializeField] int _value = 0;
    9.     }
    10.  
    11.     [CustomEditor(typeof(TestBehaviour))]
    12.     public class TestEditor : Editor
    13.     {
    14.         SerializedProperty _serializedValue;
    15.  
    16.         private void OnEnable()
    17.         {
    18.             _serializedValue = serializedObject.FindProperty("_value");
    19.         }
    20.  
    21.         public override void OnInspectorGUI()
    22.         {
    23.             base.OnInspectorGUI();
    24.  
    25.             if (GUILayout.Button("Open Window"))
    26.             {
    27.                 TestWindow.CreateWindow(target as TestBehaviour);
    28.             }
    29.  
    30.             serializedObject.ApplyModifiedProperties();
    31.         }
    32.     }
    33.    
    34.     public class TestWindow : EditorWindow
    35.     {
    36.         SerializedObject _serializedObject;
    37.         SerializedProperty _serializedValue;
    38.  
    39.         public static void CreateWindow(TestBehaviour instance)
    40.         {
    41.             CreateWindow<TestWindow>().Init(instance);          
    42.         }
    43.  
    44.         void Init(TestBehaviour instance)
    45.         {
    46.             _serializedObject = new SerializedObject(instance);
    47.             _serializedValue = _serializedObject.FindProperty("_value");
    48.         }
    49.  
    50.         private void OnGUI()
    51.         {
    52.             EditorGUILayout.LabelField("Current value: " + _serializedValue.intValue);
    53.  
    54.             if (GUILayout.Button("Add"))
    55.             {
    56.                 Debug.Log("Add Pressed");
    57.                 _serializedValue.intValue++;
    58.             }
    59.  
    60.             if(Event.current.isKey)
    61.             {
    62.                 Debug.Log("Key Pressed");
    63.                 _serializedValue.intValue++;
    64.             }
    65.  
    66.             if (Event.current.type == EventType.DragExited)
    67.             {
    68.                 Debug.Log("Drag Exited");
    69.                 _serializedValue.intValue++;
    70.             }
    71.             _serializedObject.ApplyModifiedProperties();
    72.         }
    73.     }
    74. }
     
    MelvMay likes this.
  5. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Still no idea about why it doesn't work, but I've realized about I can see the number blink to the desired one and back to original when Drag Exit. It's really weird. Seems like the objectReferenceValue is updated and rapidly back to the last value.
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,531
    Well, you could call it a bug, but I guess it's a feature ^^. The reason behind that behaviour may be that DragExited is an abort event. So no data seems to be stored during an abort event. What you have to do is actually accepting the drag operation. For this you have to do two things:
    • First you have to check in DragUpdated if you actually want to accept the drag and drop event and call
      DragAndDrop.AcceptDrag();
    • Second, in order to for Unity to accept the drag event you also have to set a "positive" visualMode. Having it set to "Rejected" or "None"(which is the default) won't actually accept the drag operation.
    When you communicate this correctly you should get a DragPerform event instead of the DragExited event. This is a "positive" event that the drag operation has been performed and the value should update. So your code should look something like:

    Code (CSharp):
    1.  
    2.         // [ ... ]
    3.         if (Event.current.type == EventType.DragUpdated)
    4.         {
    5.             DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
    6.             DragAndDrop.AcceptDrag();
    7.         }
    8.  
    9.         if (Event.current.type == EventType.DragPerform)
    10.         {
    11.             Debug.Log("Dropped");
    12.             _serializedValue.intValue++;
    13.         }
    14.         // [ ... ]
    15.  
    Keep in mind that you should actually inspect the DragAndDrop data and see if the dragged object is the one you expect or that you can accept. If not, set the visual mode to rejected.
     
    rubcc95 likes this.
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,531
    ps: using "++" on a property does actually work. It does read-modify-write the property. You just run into issues when you try to modify a field of a struct that was returned through a property. For example
    transform.position.x++;
    . Here we still read-modify-write the x field of the Vector3 value. However the actual property (position) is only read which returns a copy of the internal vector3. So the transforms position is not updated since the modified Vector3 value is not assigned back to the property.
     
  8. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Oh ty, it's working now :)
     
    MelvMay likes this.
  9. Tensor2

    Tensor2

    Joined:
    Sep 13, 2015
    Posts:
    12
    That is, in fact, not how C# works. Are you sure you've used C#? Definitely not a professional coder
     
  10. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
    That is, in fact, not how being a decent human being works. Are you sure you've heard of manners? Definitely not acting professionally.
     
    Kurt-Dekker and Bunny83 like this.
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    Please don't necro posts on these forums. Even more so if simply to insult other devs.

    Thanks.
     
    Kurt-Dekker, SisusCo and Bunny83 like this.
Thread Status:
Not open for further replies.