查找动态添加的按钮点击监听器的调用者

Find caller of dynamically added button click's listener

我正在代码中添加一个按钮列表,我想为其添加点击侦听器。

我可以添加监听器,问题是我想知道调用监听器的按钮。

我试过下面的方法,但是传给监听器的值总是一样的:

foreach (...)
{
    var button = (Button)GameObject.Instantiate(...);

    packIndex++;

    button.onClick.AddListener(() => this.OnButtonClick(packIndex));
}

public void OnButtonClick(int idx)
{
    // idx is always the latest value in the above loop
}

TL;DR

如何从按钮点击侦听器中找到调用者?

试试这个

var button = (Button)GameObject.Instantiate(...);
packIndex++;
button.name = "Button" + packIndex;
button.onClick.AddListener(() => this.OnButtonClick(button));

public void OnButtonClick(Button button)
{
// idx is always the latest value in the above loop
}

你快搞定了。要存储索引,您需要通过在 for 循环内复制 packIndex 来 "capture" packIndex 变量。可以看看这个"closure in a for loop"现象很好的解释here.

以下代码应该有效:

foreach (...)
{
    var button = (Button)GameObject.Instantiate(...);

    packIndex++;
    var packIndexCopy = packIndex;

    button.onClick.AddListener(() => this.OnButtonClick(packIndexCopy));
}

public void OnButtonClick(int idx)
{
    // idx is always the latest value in the above loop
}

请注意,@Nain 的回答也将起作用,因为在这种情况下,AddListener(() => this.OnButtonClick(button)); 中的 "button" 对象引用每次在 foreach 循环中创建的新对象,因此编译器将将 OnButtonClick 处理程序正确绑定到该 'new' 副本。事实上,直接传递 Button 对象感觉更简洁一些,但这取决于您的其余代码。

如果你不熟悉闭包(这真的很令人困惑,需要很长时间才能理解!),this article 有很好的解释。

P.S。我写了一个小组件来测试这个,这里是 gist 以防它有帮助。