Search Unity

Repaint a whole Inpector windows

Discussion in 'UIElements' started by NotGoodEnoughh, Sep 6, 2019.

  1. NotGoodEnoughh

    NotGoodEnoughh

    Joined:
    Feb 1, 2018
    Posts:
    35
    I have a custom editor and I wanna to repaint a whole inspector when it's ObjectField has changed a value.
    Code (CSharp):
    1. itemDatabase.RegisterCallback<ChangeEvent<Object>>(evt =>
    2. {
    3.     blueprintDatabase.itemDatabase = evt.newValue as ItemDatabase;
    4.     //do inspector repaint here
    5. });
    Editor.Repaint() won't work, I don't know why
    VisualElement.MarkDirtyRepaint() seems to be a wrong in this case, also it is not working
     
    Last edited: Sep 7, 2019
  2. hugobd

    hugobd

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    15
    Hello!

    Could you give more information about what you want to achieve and what are the results you are currently obtaining?
     
  3. NotGoodEnoughh

    NotGoodEnoughh

    Joined:
    Feb 1, 2018
    Posts:
    35
    I'm making a blueprint database custom editor and it needs an item database. I'm setting an item database through an object field. Then I need to show the blueprint database custom editor stuff(when I got an item database set in the object field). Also I'm saving the item database in a blueprint database to load it. Problem is that when I set an item database in the object field blueprint database stuff should show and if the object field is null it won't show anything, just the object field for item database. But it won't Repaint the editor to show those stuff.
     
  4. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    14
    Editor.Repaint is not designed for UI Elements so it doesn't work. You need to use VisualElement.MarkDirtyRepaint().
    Maybe, you need to check if:

    1: your callback is correctly called.
    Code (CSharp):
    1. itemDatabase.RegisterCallback<ChangeEvent<Object>>(evt =>
    2. {
    3.     Debug.Log("correctly called?");
    4. });
    2 : your serialized data object is correctly bound with your editor or your specific visual element.

    3 : changed data is correctly saved to serialized object.

    sample code(need to be customized for your situation):
    Code (CSharp):
    1.  
    2. public class CustomEditor : Editor
    3. {
    4.   public SerializedProperty yourData;
    5.   // get bound serialized data
    6.   public void OnEnable()
    7.   {
    8.     yourData = serializedObject.FindProperty("data-name");
    9.   }
    10.   // init inspector
    11.   public override VisualElement CreateInspectorGUI()
    12.   {
    13.     rootElement = new VisualElement();
    14.     visualTreeAsset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("your asset path");
    15.     var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("your asset path");
    16.   ...
    17.   ...
    18.   // regist callback
    19.   yourVisualElement.RegisterCallback<ChangeEvent<YourDataClass>>(CallbackFunc);
    20.  
    21.   return rootElement;
    22.   }
    23.  
    24.  void ChangeDataAndRepaint(){
    25.     // get latest data from serialized object
    26.     serializedObject.Update();
    27.     // change data like this.
    28.     var your_index = n;
    29.     if(yourData.isArray){
    30.       yourData.GetArrayElementAtIndex(your_index).intValue = 128;
    31.     }
    32.    // save changed data to bound database object.
    33.    serializedObject.ApplyModifiedProperties();
    34.    // repaint visual element
    35.    yourVisualElement.MarkDirtyRepaint();
    36.    // if you need to send event to your visual element
    37.    using (var changeEvent = ChangeEvent<YourDataClass>.GetPooled())
    38.         {
    39.           changeEvent.target = yourVisualElement;
    40.           yourVisualElement.SendEvent(changeEvent);
    41.         }
    42.   }
    43.  
    44.   void CallbackFunc(){
    45.     Debug.Log("Event Arrived!");
    46.   }
    47. }
    48.  
     
    Last edited: Sep 7, 2019
  5. NotGoodEnoughh

    NotGoodEnoughh

    Joined:
    Feb 1, 2018
    Posts:
    35
    Okay, I wrote some code like my blueprint database editor. Can you please show me what am I doing wrong.

    RepaintTest:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class RepaintTest : MonoBehaviour
    6. {
    7.     public bool test;
    8. }
    UXML:
    Code (CSharp):
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <UXML xmlns="UnityEngine.UIElements" xmlns:ui="UnityEditor.UIElements">
    3.     <Toggle name="test-toggle" label="Test"/>
    4. </UXML>
    Editor:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. using UnityEditor.UIElements;
    5. using PopupWindow = UnityEngine.UIElements.PopupWindow;
    6.  
    7. [CustomEditor(typeof(RepaintTest))]
    8. public class RepaintTestEditor : Editor
    9. {
    10.     private VisualElement root;
    11.     private PopupWindow popup;
    12.     private RepaintTest repaintTest;
    13.  
    14.     public override VisualElement CreateInspectorGUI()
    15.     {
    16.         repaintTest = target as RepaintTest;
    17.  
    18.         root = new VisualElement();
    19.         root.Clear();
    20.  
    21.         // Import UXML
    22.         var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/Editor/RepaintTestEditor.uxml");
    23.         visualTree.CloneTree(root);
    24.  
    25.         Toggle testToggle = root.Q<Toggle>("test-toggle");
    26.         testToggle.SetValueWithoutNotify(repaintTest.test);
    27.         testToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
    28.         {
    29.             //Debug.Log(evt.newValue); // -- called
    30.             repaintTest.test = evt.newValue;
    31.  
    32.             //here it needs to be repainted and passed through the statment below to draw a popup
    33.             root.MarkDirtyRepaint(); //won't work
    34.         });
    35.  
    36.         if (repaintTest.test)
    37.         {
    38.             DrawPopup();
    39.         }
    40.  
    41.         return root;
    42.     }
    43.  
    44.     private void DrawPopup()
    45.     {
    46.         if (popup != null)
    47.         {
    48.             //remove previouse popup to show new
    49.             popup.RemoveFromHierarchy();
    50.         }
    51.  
    52.         popup = new PopupWindow()
    53.         {
    54.             name = "test-popup",
    55.             text = "Test popup"
    56.         };
    57.  
    58.         Button removeBtn = new Button(() =>
    59.         {
    60.             popup.RemoveFromHierarchy();
    61.             repaintTest.test = false;
    62.             root.MarkDirtyRepaint(); //needed to update the toggle. Also won't work
    63.         })
    64.         {
    65.             name = "remove-button",
    66.             text = "Remove popup"
    67.         };
    68.  
    69.         popup.Add(removeBtn);
    70.  
    71.         root.Add(popup);
    72.     }
    73. }
     
  6. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    14
    I'm sorry. MarkDirtyRepaint doesn't seem to work in this case. I'll show you another workaround.
    (Disclaimer : just a prototype sample. tested on 2019.3.0b2)
    RepaintTestEditor.cs :
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. using UnityEditor.UIElements;
    5. using PopupWindow = UnityEngine.UIElements.PopupWindow;
    6.  
    7. [CustomEditor(typeof(RepaintTest))]
    8. public class RepaintTestEditor : Editor
    9. {
    10.   VisualTreeAsset visualTree;
    11.   RepaintTest _boundData;
    12.   private VisualElement root;
    13.   private Toggle testToggle;
    14.   private PopupWindow popup;
    15.   private RepaintTest repaintTest;
    16.   private SerializedProperty true_or_false;
    17.  
    18.   void OnEnable()
    19.   {
    20.     true_or_false = serializedObject.FindProperty("test");
    21.   }
    22.   public override VisualElement CreateInspectorGUI()
    23.   {
    24.     root = new VisualElement();
    25.     visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/Editor/RepaintTestEditor.uxml");
    26.     Forcedraw();
    27.     _boundData = (RepaintTest)target;
    28.     _boundData.root = root;
    29.     root.RegisterCallback<ChangeEvent<RepaintTest>>(evt =>
    30.     {
    31.       Forcedraw();
    32.     });
    33.     return root;
    34.   }
    35.  
    36.   private void Forcedraw()
    37.   {
    38.     root.Clear();
    39.     visualTree.CloneTree(root);
    40.     var new_toggle = new Toggle();
    41.     new_toggle.BindProperty(true_or_false);
    42.     new_toggle.label = "On/Off Flag : ";
    43.     root.Add(new_toggle);
    44.     DrawPopup();
    45.   }
    46.  
    47.   private void DrawPopup()
    48.   {
    49.     if (true_or_false.boolValue)
    50.     {
    51.       if (popup != null)
    52.       {
    53.         popup.RemoveFromHierarchy();
    54.       }
    55.       popup = new PopupWindow()
    56.       {
    57.         name = "test-popup",
    58.         text = "Test popup"
    59.       };
    60.       Button removeBtn = new Button(() =>
    61.       {
    62.         serializedObject.Update();
    63.         true_or_false.boolValue = false;
    64.         serializedObject.ApplyModifiedProperties();
    65.         popup.RemoveFromHierarchy();
    66.  
    67.       })
    68.       {
    69.         name = "remove-button",
    70.         text = "Remove popup"
    71.       };
    72.       popup.Add(removeBtn);
    73.       root.Add(popup);
    74.     }
    75.     else
    76.     {
    77.       if (popup != null)
    78.       {
    79.         popup.RemoveFromHierarchy();
    80.       }
    81.     }
    82.   }
    83. }
    RepaintTest.cs :
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UIElements;
    5. using UnityEditor.UIElements;
    6.  
    7. public class RepaintTest : MonoBehaviour
    8. {
    9.   public VisualElement root;
    10.  
    11.   public bool test = false;
    12.  
    13. #if UNITY_EDITOR
    14.   void OnValidate()
    15.   {
    16.     if ((!Application.isPlaying) && Application.isEditor)
    17.     {
    18.       if (root != null)
    19.       {
    20.         // send event
    21.         using (var changeEvent = ChangeEvent<RepaintTest>.GetPooled())
    22.         {
    23.           changeEvent.target = root;
    24.           root.SendEvent(changeEvent);
    25.         }
    26.       }
    27.     }
    28.   }
    29. #endif
    30. }
    UXML file is not needed and should be empty in this example.

    There may be another better way to achieve this.
     
    Last edited: Sep 8, 2019
    NotGoodEnoughh likes this.
  7. NotGoodEnoughh

    NotGoodEnoughh

    Joined:
    Feb 1, 2018
    Posts:
    35
    Thank you for reply! I will try it and try to make it better in my case.