我正在使用Visual Studio 2017和C#来创建Win Form应用程序。我正在尝试将鼠标输入行为添加到一组控件中,如下所示;
int i = 0;
foreach(MetroTileItem item in game_tile_panel.Items){
// THIS MESSAGE BOX DISPLAYS THE CORRECT VALUE
MessageBox.Show(i.ToString());
item.MouseEnter += (Object sender, EventArgs e) => {
// THIS MESSAGE BOX DOES NOT DISPLAY TO CORRECT VALUES
MessageBox.Show(i.ToString());
};
i++;
}
第一个消息框为每个项目返回i
的值并正确显示。 MouseEnter
行为中的第二个消息框不会显示i
的正确值,也不会显示我期望的值。
当我在运行时执行MouseEnter
行为时,消息框会为每个项目显示值3
。我希望第一项显示0
,第二项1
等。
任何人都可以解释为什么会发生这种情况以及如何解决这个问题。也许我无法以这种方式添加行为?感谢
答案 0 :(得分:1)
int i = 0;
foreach(MetroTileItem item in game_tile_panel.Items){
int pickMe = i; <<<<<<<<<<<<<
// THIS MESSAGE BOX DISPLAYS THE CORRECT VALUE
MessageBox.Show(i.ToString());
item.MouseEnter += (Object sender, EventArgs e) => {
// THIS MESSAGE BOX DOES NOT DISPLAY TO CORRECT VALUES
MessageBox.Show(pickMe.ToString()); <<<<<<<<<<<<<<<<
};
i++;
}
通过为每次迭代声明一个新变量,可以捕获正确的值。直到foreach
完成后某个时间才调用事件处理程序的事实是原因。
答案 1 :(得分:1)
这是modified closure现象的一个实例:简而言之,您声明为事件处理程序的委托捕获变量 i,而不是当前值我这称为闭包。因此,每个事件处理程序在调用它时将值3取消引用,因为这是在循环退出时你离开i的方式。
博客文章解释了如何使用局部变量来规避这一点。