0

i'm attempting to hook EventHandler onto object created dynamically. In this sample, i use simple windows .Net TabControl to contain the dynamic object. For simplicity i use Button and its Click event. The main point is button click on each TabPage should produce different output.

public partial class Form1 : Form
{
    int letter = 65;

    private void simpleButton1_Click(object sender, EventArgs e)
    {
        TabPage newPage = new TabPage();

        tabControl1.TabPages.Add(newPage);

        Button btn = new Button();

        newPage.Controls.Add(btn);

        btn.Click += (object s, EventArgs ee) =>
        {
            // Button on FirstPage should produce "Test A"
            // Button on SecondPage should produce "Test B"
            Debug.WriteLine("Test " + (char)letter);
        };

        letter++;
    }
}

However, whichever button i clicked on any page produce the output of the last page (i.e. 4 TabPages, all buttons click produce "Test D"). It felt as if the reference pointer Button btn points to all instances of button on every page.

My assumption:

Button btn = new Button();

Won't the pointer btn points to new instance of Button each time this line execute? in that sense:

btn.Click += (object s, EventArgs ee) =>

The btn.Click supposed to be the EventHandler for newly created instance of Button, right? It seems as if the pointer btn still refer to all instances of Button.

Please do enlighten me on this matter. Thank you in advance.

Suwandy
  • 45
  • 1
  • 10

2 Answers2

1

The lambda expression is capturing a reference to the letter field defined in the class, so the method will always use the latest value that is stored within it.

To capture the value of letter when the button is created, first create a local variable to copy the int value then capture the local variable in the lambda expression.

// Create a copy of the value
var character = (char)letter;

// Now the lambda will capture the local variable
btn.Click += (object s, EventArgs ee) =>
{
    Debug.WriteLine("Test " + character);
};

This works the same way for for loops.

See:

Community
  • 1
  • 1
Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92
0

A variable can only hold a single value.

You have N different buttons and N different event handlers.

However, you only have one letter field, so they all do the same thing.

Instead, you can make a local variable inside the function; then, each button will use its own variable via closures.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • You mean the value type `letter` ? – Suwandy May 08 '17 at 16:55
  • I see, it seems value type `letter` not suitable for the task i'm attempting. How can i assign different "parameters" for each EventHandler? I want Button on Page1 print "Test A", PageN print "Test N". Do i need to customize the event object, like adding property? – Suwandy May 08 '17 at 17:02
  • @Suwandy: It has nothing to do with value types. – SLaks May 08 '17 at 17:02