what is the proper why to update a custom inspector when a value changes?

I’m used to working with IMGUI for custom inspectors but decided to give UI toolkit a chance,
I’m trying to create a custom inspector, and I can’t figure out how to refresh the inspector when a value changes, to draw a section when a condition is met.

there are a few problems I’m encountering,

  1. the refresh function is being called right after the inspector is being created even if the value has not actually changed, originally i thought it was triggered during the creation of the inspector but i have put the is initialized flag and noticed its being triggered right after the creation.
  2. if I refresh the view the characterConfigField property field dosent show anymore, I suspect its because unity binds the property only once, but if i try to manually bind it again it goes into a loop of refreshing because the value change callback is being called no matter what right after the inspector is being created.

So, does anyone know what is the secrete sauce to refresh an inspector when a value changes?
The documentation only shoes simple examples and does not touch this subject

this is the main part of my code
Code

private ProceduralAnimator _animator;

private VisualElement _root;
private SerializedProperty _characterConfigProp;

private int selectedComponentIndex;
private int selectedPropertyIndex;

private bool _initialized;

private void OnEnable()
{
    _initialized = false;
    _animator = (ProceduralAnimator)target;
    _characterConfigProp = serializedObject.FindProperty("characterConfig");
    _animator.OnRequestReset += OnReset;

    VerifyBindings();
}

private void OnDisable()
{
    _animator.OnRequestReset -= OnReset;
}

public override VisualElement CreateInspectorGUI()
{
    serializedObject.Update();

    if (_root == null)
        _root = new VisualElement();

    PropertyField characterConfigField = new PropertyField(_characterConfigProp);
    _root.Add(characterConfigField);

    characterConfigField.RegisterValueChangeCallback((evt) => { VerifyBindings(); Refresh(); });

    if(_characterConfigProp != null && _characterConfigProp.objectReferenceValue != null)
    {
        foreach (AnimatorChannelBinding channelBinding in _animator.channelBindings)
        {
            BoxedFoldoutElement boxedFoldout = new BoxedFoldoutElement();
            boxedFoldout.SetFoldout(channelBinding.channelConfig.name, null, "", BoxedFoldoutElement.ColorCode.channel);
 
            _root.Add(boxedFoldout);
        }
    }

    _initialized = true;
    return _root;
}

private void Refresh()
{
    if (!_initialized) return;

    Debug.Log("Refreshing");
    serializedObject.ApplyModifiedProperties();
    _root.Clear();
    CreateInspectorGUI();
}

If the values are correctly bound to a serialized value, there will be no need to manually update the inspector when the values changes. It will happen automatically.

Also calling CreateInspectorGUI isn’t really going to accomplish much as you do nothing with the return value. It should only be called by Unity.

Thanks,
I’m trying to draw a section when a condition is met.

You could use the RegisterValueChangedCallback on the characterConfig Property to add/remove the conditional elements

Edit: I see you already are, sorry. Instead of calling Refresh and redrawing the entire layout, why not just add/remove the conditional elements when the value changes. You can also control visibility of VisualElements with the .visible property.

3 Likes

Yeah that is what i’m doing now, also created an UXML template for this, the .visible is a cool idea :slight_smile:
Thanks!

While this is a quick solution, it won’t work with undo/redo. Just use the usual SerializedObject but pair it with TrackPropertyValue to track the changes or wrap the SO in the RegisterValueChangedCallback if you still insist on using it