我正在创建一个控件数组并将它们添加到表单中,并将它们的事件设置为一个函数,该函数使用lambda表达式(b.Click += (sender, e) => myClick(i);
)接收所单击按钮的索引。
但问题是......无论你点击什么,你都会收到索引100,而不是按钮的真实索引!这有什么问题?
namespace testArrayOfControls
{
public partial class Form1 : Form
{
Button[] buttons;
public Form1()
{
InitializeComponent();
buttons = new Button[100];
for (int i = 0; i < 100; i++)
{
buttons[i] = new Button();
buttons[i].SetBounds(i % 10 * 50, i / 10 * 50, 50, 50);
buttons[i].Click += (sender, e) => myClick(i);
this.Controls.Add(buttons[i]);
}
}
private void myClick(int i)
{
MessageBox.Show(i.ToString());
}
}
}
答案 0 :(得分:5)
问题是您在循环变量i
上创建了闭包。在将它传递给事件处理程序之前,您需要创建一个本地(在for
循环内)的副本。
for (int i = 0; i < 100; i++)
{
var index = i; // YOU NEED TO DO THIS
buttons[i] = new Button();
buttons[i].SetBounds(i % 10 * 50, i / 10 * 50, 50, 50);
buttons[i].Click += (sender, e) => myClick(index); // THIS SOLVES THE PROBLEM
this.Controls.Add(buttons[i]);
}
<强>解释强>
您正在定义一个这样的函数:
(sender, e) => myClick(i)
此功能(将在未来的某个时刻运行,单击按钮时)包含对i
的引用。这样做的方法是,它会在点击发生时使用i
的值,而不是在定义函数时。
到那时,显然i
的价值将变为100。
解决方案有效,因为它使函数引用变量index
而不是i
。 index
与i
的不同之处在于i
是一个值更改的变量,而index
是我们用于100个不同变量的名称(每个循环迭代一个),< em>其值保持不变。
答案 1 :(得分:3)
问题与修改后的闭包有关。 Here是@Jon Skeet对这个主题的一个很好的解释。
答案 2 :(得分:0)
int index = i;
buttons[i].Click += (sender, e) => myClick(index);
试试吧。
答案 3 :(得分:0)
不幸的是,闭包(在你的情况下是变量i)不像它们应该在C#中那样工作。 替换
b.Click += (sender, e) => myClick(i);
带
Action<int,Button> act = (index,b) => { b.click += (sender, e) => myClick(index) }
act(i,b);