From custom editors when you change something that you know affects the layout / content of the GUI you can force a redraw using Repaint()
How would you do this from a Property Drawer? It seems like there isn’t a way to reference the Editor that contains the Property Drawer to call the Repaint.
Immediate Repaint of the current inspector without reflection or anything funny, works and tested:
public static void RepaintInspector(SerializedObject BaseObject)
{
foreach (var item in ActiveEditorTracker.sharedTracker.activeEditors)
if (item.serializedObject == BaseObject)
{ item.Repaint(); return; }
}
How does it work?
It utilizes an undocumented unity class called ActiveEditorTracker, Very USEFUL class that shows you all the Active editors in the inspector. to find the Actual editor the property drawer is a part of we iterate until we find the editor with the SerializedObject the same as our property, we then repaint it.
This class is like magic, I have been doing editor improvements for the last month and a half and it has been a godsend. (you can use it to draw OnSceneGUI from a property drawer as well with some tricks) Would love to see it actually documented.
I know this is an extremely old question but if someone comes across this and is looking for the real solution this is it.
Ok, I know I’m late to the party but this worked for me and it might help others:
I check if the object has changed and then inside my check I apply those changed properties and update. I’ve not included the dirty checking as that’s likely to change a lot between implementations anyway.
All the Repaint method in an editor actually does, is calling a static method in the InspectorWindow class. Unfortunately this class is an internal class. So you basically have two options:
Create a temporary instance of an Editor to get your hands on the Repaint method and use DestroyImmediate right after it.
Use reflection to call the static method manually.
I would go for the second solution:
public static class InspectorHelpers
{
private static System.Reflection.MethodInfo m_RepaintInspectors = null;
public static void RepaintAllInspectors()
{
if (m_RepaintInspectors == null)
{
var inspWin = typeof(EditorApplication).Assembly.GetType("UnityEditor.InspectorWindow");
m_RepaintInspectors = inspWin.GetMethod("RepaintAllInspectors", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic );
}
m_RepaintInspectors.Invoke(null, null);
}
}
Haven’t tested the class but it should work this way
There may be a way to reference the Editor in question, but I haven’t found one. What I have done instead is to ask the object that the PropertyDrawer represents, whether it wants to be repainted from your CustomEditor class. I suspect there is a more elegant way, but this is what works for me.
[CanEditMultipleObjects]
[CustomEditor(typeof(YourClass)) ]
public class YourCustomEditor : Editor
{
public override void OnInspectorGUI ()
{
serializedObject.Update();
base.OnInspectorGUI ();
serializedObject.ApplyModifiedProperties();
YourClass lite = (YourClass) target;
if ( lite.ShouldRepaint() )
{
Repaint ();
}
}
}
If none of the provided solutions worked, here’s an alternative.
My issue was: Inside a PropertyDrawer, I open a popup, which invokes a callback when a choice has been picked. After the pick, I need to repaint and re-layout the property drawer.
My solution is: Use a PopupCallbackInfo class (or similar), just like Unity does internally for some of its popups (Unity source code). NB: It’s internal and you’ll need to copy/paste or code it yourself.
// get a control id
int id = GUIUtility.GetControlID("SomeName".GetHashCode(), FocusType.Keyboard, position);
// When newIndex != currentIndex, you'll know a choice has been picked from the window
int newIndex = PopupCallbackInfo.GetSelectedValueForControl(id, currentIndex);
// A button I used to launch the popup
if (GUI.Button(position, names[currentIndex], EditorStyles.popup))
{
// create a new instance with the control id
PopupCallbackInfo.instance = new(id);
// launch your popup, and as a callback delegate, pass in the PopupCallbackInfo's method
mySearchWindow.OpenFromGUI(position, title, items, PopupCallbackInfo.instance.SetEnumValueDelegate);
}