Reputation: 831
I have following code for creating dynamic buttons but message box allways shows 8. How would I make it show in example 4 when I click button[0][4]
? I have tried labda and delegate but both allways return 8 (text[i].Count
). The same things happen to variable i
.
It must be something very simple but I can't find it :-(.
private void Form1_Load(object sender, EventArgs e)
{
for(int i = 0; i < text.Count; i++) // text.Count is 3
{
for(int a = 0; a < text[i].Count; a++) // text[i].Count is 8
{
button[i][a].Location = new Point(230, 30 +22 *a);
button[i][a].Text = "Done" + i + " " + a;
button[i][a].Click += delegate { click(a); };
...
private void click(int a)
{
MessageBox.Show("" +a);
}
Upvotes: 2
Views: 153
Reputation: 65107
Since SLaks hasn't yet given an example.. I will. Here is a small re-creation of your issue:
internal class Test
{
public EventHandler Click;
}
..then main method:
var list = new List<Test>();
for (int i = 0; i < 6; i++)
{
Test t = new Test();
t.Click += delegate
{
click(a);
};
list.Add(t);
}
foreach (var t in list)
{
t.Click(null, null); // 6, 6, 6, 6, 6
}
You need to create a local variable inside the loop, so each closure gets its own copy:
var list = new List<Test>();
for (int i = 0; i < 6; i++)
{
int a = i; /* <--------------- THIS LINE HERE ------------------ */
Test t = new Test();
t.Click += delegate
{
click(a); // use the new variable here
};
list.Add(t);
}
foreach (var t in list)
{
t.Click(null, null); // 0, 1, 2, 3, 4, 5
}
Which produces the correct output.
Upvotes: 2
Reputation: 888263
You're capturing the loop variable inside the closure.
When the event fires, that variable is always equal to the last item.
Instead, you need to declare separate variables inside the loop, so each each lambda will capture its own variable that never changes.
Upvotes: 4