开发者

Lambda expression not working in setting the event-handler of some controls

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 10开发者_运维百科0, 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());
        }

    }
}


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.


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


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

Try that.


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);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜