Define OnClick.AddListener using for loop variable

I have an inventory UI script where I want to populate an array of the buttons for each slot and set an AddListener for each button - but do this from a loop:

private Button[] InventoryUIButton;
...
private void Start()
    {
    InventoryUIButton = new Button[GlobalParams.NumberOfInventorySlots];
...
        // Get all the UI buttons for each slot and set listener
        for (int i = 0; i < GlobalParams.NumberOfInventorySlots; i++)
        {
            InventoryUIButton[i] = InventoryUISlotsParent.transform.GetChild(i).gameObject.transform.GetChild(0).gameObject.GetComponent<Button>();
            InventoryUIButton[i].onClick.AddListener(() => ProcessInventoryButton(i));
        }

...

    private void ProcessInventoryButton(int buttonIndex)
    {
        Debug.Log("Button hit " + buttonIndex);
    }

My intention is that when I click on button 4, I would see “Button hit 4”, but instead every button results in ouput “Button hit 8” (as I currently have it set to have 8 inventory slots.)

So I’d like to declare the AddListener using the variable at time of setting it, but not reference the variable later on - if that makes sense.

I’ve tried the AddListener with a delegate but same results.

InventoryUIButton[i].onClick.AddListener(delegate { ProcessInventoryButton(i); });

Have found a few threads on here that seem to address this, but I’m still unclear how to achieve this.

You need to make a copy of the loop variable when doing this

private Button[] InventoryUIButton;
...
private void Start()
    {
    InventoryUIButton = new Button[GlobalParams.NumberOfInventorySlots];
...
        // Get all the UI buttons for each slot and set listener
        for (int i = 0; i < GlobalParams.NumberOfInventorySlots; i++)
        {
            InventoryUIButton[i] = InventoryUISlotsParent.transform.GetChild(i).gameObject.transform.GetChild(0).gameObject.GetComponent<Button>();

            int iCopy = i;
            InventoryUIButton[i].onClick.AddListener(() => ProcessInventoryButton(iCopy));
        }
...
    private void ProcessInventoryButton(int buttonIndex)
    {
        Debug.Log("Button hit " + buttonIndex);
    }
5 Likes

Ah, right - got it. Thank you, works great!!!