Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Define OnClick.AddListener using for loop variable

Discussion in 'Scripting' started by dhenion65, May 3, 2020.

  1. dhenion65

    dhenion65

    Joined:
    Dec 17, 2019
    Posts:
    21
    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:

    Code (csharp):
    1. private Button[] InventoryUIButton;
    2. ...
    3. private void Start()
    4.     {
    5.     InventoryUIButton = new Button[GlobalParams.NumberOfInventorySlots];
    6. ...
    7.         // Get all the UI buttons for each slot and set listener
    8.         for (int i = 0; i < GlobalParams.NumberOfInventorySlots; i++)
    9.         {
    10.             InventoryUIButton[i] = InventoryUISlotsParent.transform.GetChild(i).gameObject.transform.GetChild(0).gameObject.GetComponent<Button>();
    11.             InventoryUIButton[i].onClick.AddListener(() => ProcessInventoryButton(i));
    12.         }
    13.  
    14. ...
    15.  
    16.     private void ProcessInventoryButton(int buttonIndex)
    17.     {
    18.         Debug.Log("Button hit " + buttonIndex);
    19.     }

    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.
    Code (csharp):
    1. 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.
     
  2. ZO5KmUG6R

    ZO5KmUG6R

    Joined:
    Jul 15, 2010
    Posts:
    490
    You need to make a copy of the loop variable when doing this

    Code (CSharp):
    1. private Button[] InventoryUIButton;
    2. ...
    3. private void Start()
    4.     {
    5.     InventoryUIButton = new Button[GlobalParams.NumberOfInventorySlots];
    6. ...
    7.         // Get all the UI buttons for each slot and set listener
    8.         for (int i = 0; i < GlobalParams.NumberOfInventorySlots; i++)
    9.         {
    10.             InventoryUIButton[i] = InventoryUISlotsParent.transform.GetChild(i).gameObject.transform.GetChild(0).gameObject.GetComponent<Button>();
    11.  
    12.             int iCopy = i;
    13.             InventoryUIButton[i].onClick.AddListener(() => ProcessInventoryButton(iCopy));
    14.         }
    15. ...
    16.     private void ProcessInventoryButton(int buttonIndex)
    17.     {
    18.         Debug.Log("Button hit " + buttonIndex);
    19.     }
     
    Westland and MangoramaStudio like this.
  3. dhenion65

    dhenion65

    Joined:
    Dec 17, 2019
    Posts:
    21
    Ah, right - got it. Thank you, works great!!!