0

I am using Visual Studio 2017 and C# to create a Win Form application. I am trying to add mouse enter behaviour to a set of controls as follows;

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++;
}

The first message box returns the value of i for each item and displays correctly. The second message box, inside of the MouseEnter behaviour does not display the correct values for i, or atleast not the values I am expecting.

When I perform the MouseEnter behaviour at runtime the message box displays the value 3 for every item. Whereas I would expect the first item to display 0, the second item 1 ect.

Can anyone shed should light on why this is happening and how I might fix it. Perhaps I am not able to add behaviours in this manner? Thanks

Mark
  • 691
  • 7
  • 20
  • 1
    you can read about closures in more detail on this [answer](https://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp) – Borka Jan 02 '18 at 23:12

2 Answers2

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++;
}

By declaring a new variable for each iteration the correct value gets captured. The fact that the event handler is not called until sometime(s) after the foreach is completed is why.

radarbob
  • 4,964
  • 2
  • 23
  • 36
1

This is an instance of the modified closure phenomenon: in short, the delegate you declare as the event handler captures the variable i, not the current value of i. This is called a closure. Therefore each event handler dereferences i with value 3 at the time that it's called because that's how you left i when the loop exited.

The blog post explains how to circumvent this using a local variable.

Tom W
  • 5,108
  • 4
  • 30
  • 52