2014-01-10 103 views
2

我有以下用於創建動態按鈕的代碼,但消息框總是顯示8.我如何使它在示例4中顯示,當我單擊button[0][4]時?我已經試過labda和委託,但總是返回8(text[i].Count)。同樣的事情發生在變量i。 它必須是很簡單的東西,但我不能找到它:-(。將變量傳遞給Click事件

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

回答

4

你捕捉封閉內循環變量。
事件觸發時,該變量總是等於最後一個項目。

相反,你需要聲明循環內不同的變量,因此每個每個拉姆達將捕捉自己的變量,它永遠不會改變。

+0

難道這個「突破性改變」很快就會發生......?變量在循環內部的位置? –

+0

我不確定,但在這種特殊情況下,他使用的是int,而不是引用類型。所以看起來好像一切都會好的 – Anarion

+0

@SLaks你是說聲明'int newVariable = a'和'委託{click(newVariable);};'會解決這個問題嗎?我同意它會拿起最後一個值,但我不太確定聲明一個新的變量將解決這個問題......我認爲這需要一個不同的解決方案。 – CarbineCoder

2

由於SLaks還未給出的例子..我會。以下是您的問題的重新創建:

internal class Test 
{ 
    public EventHandler Click; 
} 

..then主要方法:

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 
} 

您需要創建循環中的局部變量,所以每封都有自己的副本:

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 
} 

將會產生正確的輸出。