-1

I am trying to add some buttons to a control programmatically using a for-statement.

What I wish to accomplish is that every button fires the click event with the iterator value inside.

Here is an example of my code:

public class Foo
{ 
    public Foo(int val)
    {
     //Do something with val
    }
}

//for-statement
for(int i = 0; i < 5; ++i)
{
    var button = new Button();
    button.Click += (sender, e) =>
    {
        var text = new Foo(i);
    }
}

In my scenarios it intializes Foo with the last value of the iterator, that being 4.

How can I accomplish to send every value of the iterator?

Button1->Click->Foo(0)

Button2->Click->Foo(1)

... and so on.

  • What did you try? – BugFinder Dec 13 '16 at 11:18
  • `public class ValueWrapper where T : struct { T _Value; public T Value { get { return _Value; } set { _Value = value; } } public ValueWrapper(T initial) { _Value = initial; } }` and then use `var @int = new ValueWrapper(i); button.Click += (sender, e) => { var text = @int; };` – mrogal.ski Dec 13 '16 at 11:20
  • 1
    See this question: https://stackoverflow.com/questions/2226510/closures-in-c-sharp-event-handler-delegates – Peter B Dec 13 '16 at 11:20
  • @PeterB, that's a good (quite similar) duplicate, thanks for finding. – Sinatr Dec 13 '16 at 11:31

3 Answers3

2

You fall in the trap of closures. Use Button.Tag instead.

public class Foo
{ 
    public Foo(int val)
    {
     //Do something with val
    }
}

//for-statement
for(int i = 0; i < 5; ++i)
{
    var button = new Button();
    button.Tag = i;
    button.Click += (sender, e) =>
    {
        var text = new Foo((int)((sender as Button).Tag));
    }
}
Community
  • 1
  • 1
Nick
  • 4,787
  • 2
  • 18
  • 24
0

You can add a Tag to your Button like this

for(int i = 0; i < 5; ++i)
{
    var button = new Button();
    button.Tag = i; 
    button.Click += Button_Click();
}

And then cast object sender back to Button to receive the tag

private void Button_Click(object sender, RoutedEventArgs e)
{
    var button = (Button)sender;
    var tag = (int)button.Tag;
}
mammago
  • 247
  • 2
  • 13
-1

It's a well known problem, which is hard to find in fact (I fail to find something simple, therefore writing an answer). Change your for to capture loop variable value inside:

for(int i = 0; i < 5; ++i)
{
    var current = i; // capture ('for' scope local variable to hold current value of i)
    var button = new Button();
    button.Click += (sender, e) => var text = new Foo(current); // don't use i here
}
Sinatr
  • 20,892
  • 15
  • 90
  • 319