Button.onClick headache when trying to Add a listerer in a component of a prefab.

I have a button prefab that I am instantiating at runtime and I am trying to be notified of the Unity button’s onClick() event. After consulting the forums and making a few different attempts, here is my last effort:

void Start()
    {
        Button btn = gameObject.GetComponent<Button>();
        btn.onClick.AddListener(delegate { OnButtonClick(); });        
    }

public void OnButtonClick()
    {
        _justClicked = true;
        PostEventNotification(EVENT_TYPE.OnGameSpriteTextureClick);
    }

I am still receiving the exact same error:

Yeah, that error isn’t very descriptive and, if you’re using an earlier beta, is missing the correct stack trace. The most common cause I’ve seen here is that something, somewhere is null.

I’m using b17. b18 is out but not fully tested. Your answer narrowed it down, but thanks for the response. :slight_smile:

I have tried dragging the component of the prefab into the OnClick event field in the Inspector and also leaving it empty in conjunction with the code shown above. Is there something else maybe I can try?

I believe that particular snippet should work without an EventTrigger due to onClick being a Button property, but don’t quote me on that. What exactly isn’t working? Are you still getting errors?

Yes, it is still not working. Same error and same description as above. It doesn’t change no matter what I put into the onClick method in the Inspector.

Ok, so two first steps to fixing this puppy then:

  1. Remove either the code to add a Listener to onClick, or remove it from the editor list. Let’s keep this problem as basic as possible, without redundanicies. =)

  2. Figure out where that error is coming from; it could be anywhere. Does it only happen when you click the button? If so, try commenting your method’s body line by line to try and find the cause. If not, do null checks elsewhere. Is btn assigned to properly? Was the Component perhaps not found? Stuff like that.

This is a minimal component for adding to a button or other canvas element that needs to respond to a click event:

using UnityEngine;
using UnityEngine.EventSystems;

public class Click : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData data)
    {
        Debug.Log("Clicked at "+data.position.x+","+data.position.y);
    }
}
1 Like

Whats the full error in the log? There should be a stacktrace there that points to the line the error is happening on (it is a nested exception).

This is all I see:

First of all, thanks again for you help.

There appears to be something wrong elsewhere, external to my code file. The same error also occurs when I comment out my code and then manually add the component/method to the OnClick specification of the Button component of my prefab and then apply it to the prefab.

1 Like

Excellent, thank you very much! This solved the problem.

1 Like

Ok, I was absolutely wrong and it is time for me to eat crow. It is my code causing the problem. I must have had it commented out when I thought everything was working above. It appears that by hooking into the OnClick event for the button has hijacked my own event handling system that was previously working. Specifically, in my NotificationsManager class, I am maintaining a list of IListener objects. When I need to post a notification to those listeners, I am passing in the event type that is being listened for and then using reflection to invoke the method on the listener that matches the event type.

Here is the PostEventNotification() method from my NotificationsManager:

public void PostEventNotification(EVENT_TYPE Event_Type)
    {
        if(!_listeners.ContainsKey(Event_Type.ToString()))
            return;

        // Notify all listeners.
        foreach(IListener thisListener in _listeners[Event_Type.ToString()])
        {
            // Use Reflection to make the method call matching the EventType.
            Type type = thisListener.GetType();
            Debug.Log("Listener type: " + thisListener.GetType());
            MethodInfo method = type.GetMethod(Event_Type.ToString());
            Debug.Log("method.Name: " + method.Name);
            //method.Invoke(thisListener, null);
        }

The very last line that is commented out is where the error occurs. When I call the Invoke method on the MethodInfo instance I receive this:

So first, my apologies to all of you for leading you on a wild goose chase. However, now that I finally seem to be on the right track to solving this, I still do not understand why IPointerClickHandler is expected. TextureButton is what is sent and that is what it should be, at least that was the way it was working before tying into Unity’s events.

Relevant to this is probably the code that is run when I initially add the TextureButton object as a listener.

private Dictionary<string, List<IListener>> _listeners = new Dictionary<string, List<IListener>>();

    public void AddListener(IListener listenerObject, string EventName)
    {
        // Create new List within Dictionary representing the EventType if not already there.
        if(!_listeners.ContainsKey(EventName))
            _listeners.Add(EventName, new List<IListener>());

        // Add the listener to the correct List.
        _listeners[EventName].Add(listenerObject);
    }

And the call to AddListener() from the TextureButton class:

public void AddListener ()
    {
        GameManagerInstance.NotificationsMgr.AddListener(this, EVENT_TYPE.OnGameSpriteTextureClick.ToString());
    }

To finally solve the problem, I scrapped using reflection in .NET and decided to use it in Unity via the GameObject.SendMessage() method. So for anyone who might be interestedin the final resolution (though I don’t know why since it is completely off-topic now), here is the rewrite of the PostEventNotfification method:

public void PostEventNotification(EVENT_TYPE Event_Type)
    {
        if(!_listeners.ContainsKey(Event_Type.ToString()))
            return;

        // Notify all listeners.
        foreach(IListener thisListener in _listeners[Event_Type.ToString()])
        {
            TextureButton thisButton = thisListener as TextureButton;
            thisButton.SendMessage(Event_Type.ToString(), thisListener, SendMessageOptions.DontRequireReceiver);
        }
    }

Just a question, are you sure that is the full log? There should be a details panel (the bottom part of the console) that has a stack trace. There should always be more information there then what you have pasted here.

Attached is a pic of a button that causes a null ref on Beta 18.

Positive there was nothing else. I even triggered the exception in normal mode and in debug mode, but it did not change. What I copied and pasted here was all that appeared in the console. It actually looks identical in the upper portion of the console except it has the red icon and is not selectable whereas in the bottom part it is selectable.

I have already stripped out the offending code, but if you like I will replace it and grab a screen shot.

Would this work for a New Unity GUI Slider. I can control morp Targets with the Legacy GUI Sliders and with NGUI but canit find how to use the New Gui.

Is there a OnSlider…( ) ?

Thanks

I can see that there is a OnScrollEvent subclass of the Slider class. Seeing this, I would suspect that there is an OnScroll() that you could hook into. However, I have not attempted with any uGUI 2 events other than the OnClick() detailed above.

1 Like

Thanks