Я использую 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
Mark 3 Янв 2018 в 02:03

2 ответа

Лучший ответ
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
radarbob 2 Янв 2018 в 23:07

Это экземпляр измененного явление закрытия: короче говоря, делегат, который вы объявляете в качестве обработчика событий, захватывает переменную i, а не текущее значение i. Это называется закрытием. Поэтому каждый обработчик событий разыменовывает i со значением 3 во время его вызова, потому что именно так вы оставили i при выходе из цикла.

В сообщении блога объясняется, как обойти это с помощью локальной переменной.

1
Tom W 2 Янв 2018 в 23:09