I have a List<string> and I want to iterate over this collection and do something with each string on a button click. I have a small example here to illustrate what I’m trying to do:
//items is a System.Collections.Generic.List<string>
foreach (string s in items)
{
Button b = new Button() { Content = s };
b.Click += (obj, ev) =>
{
MessageBox.Show(s);
}
//add b to form, container, etc...
}
As you would expect the buttons are created appropriately with the correct content, however when I click any of the buttons, the text inside the MessageBox is always the last string in items. What am I missing with this? Why is it that all the Click functions for the buttons are passed the last item in the collection?
The
foreachloop is changings, which is used in the lambda. The lambda uses the current value ofsat the point of execution, not declaring it (in techspeak: “closures close over variables, not values”). You’ll have to make a local variable:Thus you have a reference to the instance of
sat the point of decleration, not execution.Eric Lippert has two fantastic articles about it: part 1, part 2.