0

Is it possible to have delegates declared in a loop perform different actions?

var buttons = new List<ImageButton>();
buttons.Add(FindViewById<ImageButton>(Resource.Id.button1));
buttons.Add(FindViewById<ImageButton>(Resource.Id.button2));
int count = 1;
foreach(var button in buttons) {
    button.Click += delegate {
        Toast.MakeText(this, "I am " + count, ToastLength.Short).Show();
    }
    count++;
}

The toast message always "I am 2" when clicking either button. Ultimately I would like to have a number of buttons performing slightly different actions when clicked.

Aaron Thompson
  • 1,849
  • 1
  • 23
  • 31
  • There are lots of questions about captured variables which are similar to this, but finding duplicates can be very hard as the contexts can be quite different. – Jon Skeet Jul 28 '17 at 10:50
  • 1
    I think I've found one which is close enough though... (I'd like this question and its answer to still exist though, for the sake of making it easier to find from similar questions in the future...) – Jon Skeet Jul 28 '17 at 10:51

2 Answers2

3

You've got a single count variable, and your anonymous method captures it. That means when the delegate is executed, it will always use the current value of that variable. You want "the value of count when the delegate was created" which means you want a different variable on each iteration. It's simplest to just declare a variable within the loop:

int count = 1;
foreach(var button in buttons) {
    // Each iteration will create a "new" copy variable, whose
    // value never changes
    int copy = count;
    button.Click += delegate {
        Toast.MakeText(this, "I am " + copy, ToastLength.Short).Show();
    }
    count++;
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

One possible solution is to tag each button then use the tag in the event handler.

var buttons = new List<ImageButton>();
buttons.Add(FindViewById<ImageButton>(Resource.Id.button1));
buttons.Add(FindViewById<ImageButton>(Resource.Id.button2));
int count = 1;
foreach(var button in buttons) {
    button.Tag = count;
    button.Click += Button_Click;
    count++;
}

private void Button_Click(object sender, System.EventArgs e)
{
    Toast.MakeText(this, "I am " + (sender as Button).Tag, ToastLength.Long).Show();
}

This however feels hacky.

Aaron Thompson
  • 1,849
  • 1
  • 23
  • 31