3

I'm creating an array of controls and adding them to the form, and setting their events to a function that receives the index of the clicked button using a lambda expression (b.Click += (sender, e) => myClick(i);).

But the problem is... Whichever you click on, you receive the index 100, not the real index of the button! What is the problem here?

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());
        }

    }
}
1

4 Answers 4

5

The problem is that you create closure over the loop variable i. You need to make a local (inside the for loop) copy of it before passing it to the event handler.

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]);
}

Explanation

You are defining a function like this:

(sender, e) => myClick(i)

This function (which will run at some point in the future, when the button is clicked) includes a reference to i. The way, this works is that it will use the value of i at the time when the click occurs, not at the time the function is defined.

By that time, clearly the value of i will have become 100.

The solution works because it makes the function take a reference to the variable index instead of i. index differs from i in that i is one variable whose value changes, while index is a name we use for 100 different variables (one for each loop iteration), the value of which remains constant.

Sign up to request clarification or add additional context in comments.

Comments

3

The problem is to do with modified closures. Here is an excellent explanation of the subject by @Jon Skeet.

Comments

0
int index = i; 
buttons[i].Click += (sender, e) => myClick(index);

Try that.

Comments

0

Unfortunately closures (in ur case the variable i) doesn't work the way they should be in C#. Replace

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

with

Action<int,Button> act = (index,b) => { b.click += (sender, e) => myClick(index) }
act(i,b);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.