0

I'm attempting to add events to buttons on a menu that is assembled at run time.

// The rest of the menu is assembled around this. There is a 'foreach' loop adding the buttons one at a time.

GameObject obj = Instantiate(quickCommandPrefab, FindCorrectHolder(c.cType).transform);

// >>>
// There are other things happening here that aren't having problems.
// >>>

//  set the event for the "button press"
btn = obj.transform.GetComponent<Button>();
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(delegate { CheckKeyPress(c.keyToActivate); });
//  There is just something about the button onClick event.

I have tried multiple slightly different syntax that still amounted to this.

These are the components of the object being instantiated.

enter image description here

I have even gone so far as to separate out that code into its own function to execute separately after the instantiation as follows:

void SetupButtonEvents()
{
    foreach (Button btn in transform.GetComponentsInChildren<Button>(true))
    {
        Button temp = btn;  // I did try a temp variable as well to see if that would help. NOPE, same problem!
        
        string keyCode = btn.transform.Find("UseKeyText").GetComponent<TextMeshProUGUI>().text;
        btn.onClick.RemoveAllListeners();
        btn.onClick.AddListener(delegate { CheckKeyPress(Enum.Parse<KeyCode>(keyCode)); });
    }
}

I've been using 'Debug.LogWarnings' to track what is going on and btn.onClick.GetPersistentEventCount() always comes back 0.

I can't say as I've had this problem before, though that is usually without Unity's own event system or using said event system through the inspector and not through code.

2
  • 1
    This is how you add runtime listeners to the button .. if this code is executed it is most likely the listener was added .. as stated in the answer below it won't appear in the inspector as here only persistent listeners will show up .. if this is editor time code and should indeed be persistent callbacks you will have to go through AddPersistentListener Commented Oct 7, 2024 at 8:06
  • It may be that I'm trying to execute the Invoke improperly. Commented Oct 7, 2024 at 20:29

3 Answers 3

3

When you look at the reference documentation of onClick type UnityEvent:

  • AddListener: Add a non persistent listener to the UnityEvent.
  • GetPersistentEventCount: Get the number of registered persistent listeners.

GetPersistentEventCount will not return a count of the listeners you added with AddListener. One handles persistent listeners, the other does not. So that approach is inadequate to verify whether listeners have been added.

Sign up to request clarification or add additional context in comments.

Comments

1

Your two code snippets do something very different. In the first snippet the context is missing. If c is a foreach loop variable, each of your anonymous delegate would capture the same variable and as a result each callback would refer to the same variable which would contain the last assigned data and not the data you're expecting.

Your second code snippet has also some questionable things in it. Do not read back text values from TextMeshPro components. Those are components that are for visualizing text and they often add invisible formatting characters to the text. Those additional characters would mess with your enum text parsing. Also you shouldn't put that Enum.Parse call inside the callback. That would mean you parse it every time you press the button. Parse it outside the delegate, save the actual key code in a local variable and let the delegate capture that variable. Though as I said, don't use TextMeshPro components to store and read back data. You could use the button's gameobject name instead as long as you renamed it in your spawning code.

So assuming the first code snippet is in a foreach loop, you should use an additional local variable

KeyCode key = c.keyToActivate;
btn.onClick.AddListener(delegate { CheckKeyPress(key); });

This should fix the first code snippet. To debug the issue you could also have added a Debug.Log("Button pressed with key " + key) call inside the delegate to see what value is actually used.

As others have already explained, UnityEvents have persistent and dynamic subscribers. The persistent subscribers are those serialized in the inspector. The dynamic ones are additional listeners that has been added at runtime. So your listener can not show up in the inspector.

1 Comment

You are very right about Enum.Parse; now I'm wondering why I didn't do something so simple in the first place. As for the TextMeshpro bit, that is a reversal of an Enum being set 'ToString(),' I'm just unwinding it. I don't really want to execute like that anyways.
1

I have to thank everyone who gave an answer or left a comment. Every last bit was useful information given the question that I was asking and the information I provided; and I realize I did forget to add important information that would have helped. Indeed, this thread made me rethink my thought processes and debugging approach which helped me find the real issue…

…and don't I feel silly.

I found that the issue I was having was not with the onClick.AddListener() but with the invocation of the onclick event which is being in handled in the script's Update() to allow for Gamepad input on the menu and was giving me a NullReferenceException. I noticed that I did forget to mention that explicitly, my bad.

Old Code Line: EventSystem.current.GetComponent<Button>().onClick.Invoke(); executed and got a nullref since there isn't a button attached to EventSystem.current.

New Code Line: EventSystem.current.currentSelectedGameObject.GetComponent<Button>().onClick.Invoke(); executes correctly, since there is a GameObject (with a button) attached to EventSystem.current.

Thank you all and I'll try not to leave out that important stuff again.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.