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

痞子三分冷 提交于 2019-12-10 19:56:43

问题


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:


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.




回答2:


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




回答3:


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

Try that.




回答4:


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


来源:https://stackoverflow.com/questions/6439477/lambda-expression-not-working-in-setting-the-event-handler-of-some-controls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!