Лямбда-выражение не работает при установке обработчика событий некоторых элементов управления - PullRequest
3 голосов
/ 22 июня 2011

Я создаю массив элементов управления и добавляю их в форму, а также устанавливаю их события для функции, которая получает индекс нажатой кнопки, используя лямбда-выражение (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());
        }

    }
}

Ответы [ 4 ]

5 голосов
/ 22 июня 2011

Проблема в том, что вы создаете замыкание по переменной цикла 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 различных переменных (по одной для каждой итерации цикла), , значение которого остается постоянным .

3 голосов
/ 22 июня 2011

Проблема заключается в модифицированных замыканиях . Здесь - превосходное объяснение предмета @Jon Skeet.

0 голосов
/ 22 июня 2011

К сожалению, замыкания (в нашем случае переменная i) не работают так, как они должны быть в C #. Заменить

b.Click += (sender, e) => myClick(i);

с

Action<int,Button> act = (index,b) => { b.click += (sender, e) => myClick(index) }
act(i,b);
0 голосов
/ 22 июня 2011
int index = i; 
buttons[i].Click += (sender, e) => myClick(index);

Попробуйте это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...