BenjaFriend BenjaFriend - 4 months ago 38
C# Question

How to add to UnityEvents of a Toggle in C# , Unity

I am creating toggle buttons programmatic in Unity at run time, and I would like to add an event to happen to these toggles.

I want to add to the Unity Event that is triggered when the toggle is clicked, but I can't seem to tie it together properly.

public Toggle myToggle_Prefab;
pulic int numberToggles;
private Toggle[] runtimeToggles;

private void Start()
{
runtimeToggles = new Toggle[numberToggles];
for(int i = 0; i < runtimeToggles.Length; i++)
{
runtimeToggles[i] = Instantiate(togglePrefab);
// ADD TO THE EVENT HERE
runtimeToggles[i].onValueChanged.AddListener(MyMethod);
}

}

private void MyMethod(int index){
// Do something
}


That doesn't work out because it is an integer paramater. The method works with a bool parameter like this:

private void MyMethod(bool arg0)
{
// Do stuff
}


But I need the integer parameter to do what I want to do. Any thoughts?

Answer Source

You do it like this:

 for(int i = 0; i < runtimeToggles.Length; i++)
 {
      runtimeToggles[i] = Instantiate(togglePrefab);
      // no-parameter version:
      runtimeToggles[i].onValueChanged.AddListener(delegate{ MyMethod(thatInteger); });
      // boolean parameter version:
      runtimeToggles[i].onValueChanged.AddListener(delegate (bool b){ MyMethod(thatInteger); });
 }

Wrap the method you want to call in a delegate (which takes either no parameters or the boolean) and call your method from there. Note that I've left thatInteger undefined, as your question doesn't indicate what the value is or is for.

Do note that if you want to pass the i value, you will need to copy it to a local-scope variable (See this question for why) first:

 for(int i = 0; i < runtimeToggles.Length; i++)
 {
      // like this:
      int thatInteger = i;
      runtimeToggles[i] = Instantiate(togglePrefab);
      // no-parameter version:
      runtimeToggles[i].onValueChanged.AddListener(delegate{ MyMethod(thatInteger); });
      // boolean parameter version:
      runtimeToggles[i].onValueChanged.AddListener(delegate (bool b){ MyMethod(thatInteger); });
 }

The boolean, by the way, I believe represents what the toggle was changed to (i.e. if it becomes checked, then that boolean passed is true).

The reason it works is because the event can invoke a narrow range of predefined delegate methods (offhand those signatures would be (), (bool state), and (UI.Toggle t) and I'm not 100% sure about that last one) covering the most probable uses of the event. Anything else has to get wrapped in a delegate that conforms to one of those; e.g. delegate{ f(int i); }, as otherwise the Unity internals don't know what it is you want to pass to your method.

No, the official documentation doesn't list these signatures (unhelpful, that) and are invoked through internal voodoo magic (like a lot of Unity MonoBehaviour methods).