Can't get GUI to rebuild

Hello!

I’ve decided to give the new UI Elements a go in the 2019.2 alpha and I’m having some issues with getting the GUI to rebuild.

Here’s the code I currently have.

public override VisualElement CreateInspectorGUI()
{
    root = new VisualElement();

    IMGUIContainer toolbarContainer = new IMGUIContainer(() =>
    {
        int newTab = GUILayout.Toolbar(m_CurrentTab, m_Tabs);
        if (newTab != m_CurrentTab)
        {
            m_CurrentTab = newTab;
            EditorPrefs.SetInt(SELECTED_TAB_PREFS, m_CurrentTab);
            RebuildTab(m_CurrentTab);
        }
    });

    root.Add(toolbarContainer);
    RebuildTab(m_CurrentTab);

    return root;
}

private void RebuildTab(int tab)
{
    if (root.Contains(cameraElements))
        root.Remove(cameraElements);

    if (root.Contains(movementElements))
        root.Remove(movementElements);

    switch (tab)
    {
        case 0:
            CreateCameraGUI();
            root.Insert(1, cameraElements);
            break;
        case 1:
            CreateMovementGUI();
            root.Insert(1, movementElements);
            break;
    }
}

private void CreateCameraGUI()
{
    cameraElements = new VisualElement();
    SerializedProperty it = m_Camera.Copy();
    while (it.NextVisible(true))
    {
        if (it.propertyPath.StartsWith(m_Camera.name) && it.depth < 2)
            cameraElements.Add(new PropertyField(it));
    }
}

When I first get to the inspector, it works no problem. But the problem occurs when using the Toolbar in the IMGUI Container. When that calls the RebuildTab function, the new GUI doesn’t get added. It does remove the old elements but doesn’t add any new ones.

I also tried to hook the RebuildTab function up to a MouseUpEvent but that didn’t change anything.

Anyone that can share some light on what’s going on here? Thanks

EDIT: I added one of the Create…GUI functions just to shed some light on what I do there.

EDIT 2: Further investigating using the UI Elements debugger shows that the property fields are there, but they are empty. To me, this sounds like a bug, but I’m going to wait for a word from anyone else.

PropertyFields need to be bound to a SerializedProperty in order to generate their internal UI fields (using the correct data type from the SerializedProperty).

When you first create your inspector in CreateInspectorGUI() and return “root”, the InspectorWindow will automatically call Bind() on your entire inspector and populate all the PropertyFields. However, in the next RebuildTab, you remove all the populated PropertyFields and replace them with fresh new PropertyFields, which the InspectorWindow does not know about. You would have to call

root.Bind(serializedObject)

to have them bound again.

That said, what I would recommend is to create all your PropertyFields and tabs in the main call to CreateInspectorGUI() and then only control which tab is visible using:
tabElement.style.display = DisplayStyle.Flex;
or
tabElement.style.display = DisplayStyle.None;

Thank you! I used your advice and toggled the elements using the style instead!

If anyone is curious, this is how my code looks now:
Code

public override VisualElement CreateInspectorGUI()
{
    root = new VisualElement();

    IMGUIContainer toolbarContainer = new IMGUIContainer(() =>
    {
        int newTab = GUILayout.Toolbar(currentTab, m_Tabs);
        if (newTab != currentTab)
        {
            currentTab = newTab;
            EditorPrefs.SetInt(SELECTED_TAB_PREFS, currentTab);
            RebuildTab(currentTab);
        }
    });

    root.Add(toolbarContainer);

    CreateCameraGUI();
    CreateMovementGUI();

    root.Add(cameraElements);
    root.Add(movementElements);
   
    RebuildTab(currentTab);

    return root;
}

private void RebuildTab(int tab)
{
    cameraElements.style.display = (tab == 0 ? DisplayStyle.Flex : DisplayStyle.None);
    movementElements.style.display = (tab == 1 ? DisplayStyle.Flex : DisplayStyle.None);
}