Runtime - SetActive(false) or enabled = false will lose event binding

I discovered that if you make a game object containing a UIDocument inactive or you disable the UIDocument. Then any event bindings will be lost.

If you need to hide the document, use root visibility instead.

For example:

public class MyClass : Monobehaviour
{
    [SerializeField]
    private UIDocument document; // set in inspector

    private void Start()
    {
        var myButton = document.rootVisualElement.Q<Button>("nameOfMyButton");
        myButton.clicked += () => Debug.Log("Button is clicked");

        document.enabled = false; // Don't do this! Event binding lost!
        gameObject.SetActive(false); // Don't do this! Event binding lost!

        document.rootVisualElement.visible = false; // DO THIS!
    }
}

In my case it was the “escape” menu that I was trying to create and then hide.

I used the UI Toolkit Event Debugger to see that the events were being fired on the buttons but no methods were called.

Posting here because it drove me mad for 3 hours.

7 Likes

Oh man, thank you. I also got this problem. You are genius

2 Likes

Wow, this is really helpful, I was looking for cause of the same issue everywhere, both gpt and muse failed to anwser, and yet you solve that, thank you!

1 Like

Indeed, this is a known workflow issue. The reason this happens is because UI Toolkit expects UI to be created and bound in the OnEnable() call. This way, it will always recover (rebuild) when you disable->enable the MonoBehaviour or GameObject. More info here:

There’s a long story here, but a reason for this pattern is to enable fast iteration when making changes to your UI assets in the Editor (ie the UI Builder, but also text editor). When we detect changes, we artificially destroy the UI hierarchy and call OnEnable() again on your MonoBehaviour to regenerate the UI with the updated assets.

That said, it is ALSO good practice with UI Toolkit to not disable the entire GameObject whenever you want to hide UI and instead, either do what you did with visible, or use the display:none style. This will keep bindings up and also save you a lot of unnecessary allocations.

1 Like