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

Question How to pass arguments to callback functions using IPointerClickHandler

Discussion in 'Scripting' started by halsamacomplex, Sep 16, 2022.

  1. halsamacomplex

    halsamacomplex

    Joined:
    Jul 23, 2022
    Posts:
    4
    Since I don't want to use the Unity genuine Button component, I'm using an alternative class for Button that I created with reference to someone else's source.
    Code (CSharp):
    1. public class CustomButton:Monobehaiviour,IPointerClickHandler{
    2.     public System.Action onClickCallback;
    3.     public void OnPointerClick(PointerEventData eventData)
    4.     {
    5.         onClickCallback?.Invoke();
    6.     }
    7. }
    However, I noticed a problem when using it in combination with List.

    Code (CSharp):
    1. private int BUTTON_NUM = 3;
    2. void Start()
    3. {
    4.     for (int i = 0; i < BUTTON_NUM; i++)
    5.     {
    6.         roomButtons[i].onClickCallback = () => {
    7.             OnClickRoomBtn(i);
    8.         };
    9.     }
    10. }
    11.  
    12. private void OnClickRoomBtn(int roomNo)
    13. {
    14.     Debug.Log("RoomNo: "+ roomNo);
    15. }
    16.  
    Click roomButtons[0] to
    > RoomNo: 3

    As mentioned above, I noticed that I can't pass the arguments as intended in the For syntax.

    Code (CSharp):
    1. void Start()
    2. {  
    3.     roomButtons[0].onClickCallback = () => {
    4.         OnClickRoomBtn(0);
    5.     };
    6.     roomButtons[1].onClickCallback = () => {
    7.         OnClickRoomBtn(1);
    8.     };
    9.     roomButtons[2].onClickCallback = () => {
    10.         OnClickRoomBtn(2);
    11.     };
    12. }
    Click roomButtons[0] to
    > RoomNo: 0

    In this way, if you write only the number of buttons, it will work, but I want to use the For statement.
    Please let me know how I can modify this format to make it more convenient.
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,016
    Simply put, you'd have to introduce your own delegate with parameters. Such as
    System.Action<int>
    .
     
    halsamacomplex likes this.
  3. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530
    Code (CSharp):
    1.     for (int i = 0; i < BUTTON_NUM; i++)
    2.     {
    3.         roomButtons[i].onClickCallback = () => {
    4.             OnClickRoomBtn(i);
    5.         };
    6.     }
    That will capture reference to i not the value of i. So all the callbacks you create refer to the same i variable. This may be slightly surprising since in rest of C# it's almost impossible to make a reference to value type variables, and parts that allow you to make something similar require to be somewhat explicit about it.

    So you need to do it this way:
    Code (CSharp):
    1.     for (int i = 0; i < BUTTON_NUM; i++)
    2.     {
    3.         int buttonNum = i;
    4.         roomButtons[i].onClickCallback = () => {
    5.             OnClickRoomBtn(buttonNum);
    6.         };
    7.     }
     
    tomfulghum and halsamacomplex like this.
  4. halsamacomplex

    halsamacomplex

    Joined:
    Jul 23, 2022
    Posts:
    4
    I just realized that I don't understand delegates very well. I will take this opportunity to study. Thank you very much.
     
  5. halsamacomplex

    halsamacomplex

    Joined:
    Jul 23, 2022
    Posts:
    4
    Thank you, I was surprised how easy it was to solve.
    It was necessary to repeat, including the definition of variables.