Reputation: 54453
I'd like to use a context menu and get the user's choice in a local variable.
I tried to use a simple lambda like this:
void showMenu(Point pos)
{
ContextMenu m = new ContextMenu();
int choice = -1;
var menueChoices = new string[] {"Stretch Mode", "Brightness", "Saturation",
"Hues", "Flip Color Stops", "Invert Colors" };
for (int i = 0; i < menueChoices.Length; i++ )
{
MenuItem mi = new MenuItem(menueChoices[i]);
mi.Index = i;
mi.Click += (sender, e) => { choice = mi.Index; };
m.MenuItems.Add(i, mi);
}
m.Show(flowLayoutPanel1, pos);
// work with the choice..
}
The choice is assigned alright in the lambda (I can print it to the Console) but is reset afterwards.
I have found in this post that according to the C# Language Specification:
5.3.3.29 Anonymous functions
For a lambda-expression or anonymous-method-expression expr with a body (either block or expression) body:
The definite assignment state of an outer variable v before body is the same as the state of v before expr. That is, definite assignment state of outer variables is inherited from the context of the anonymous function.
The definite assignment state of an outer variable v after expr is the same as the state of v before expr
OK. Now, I realize that I could create a non-anonymous function but I'd really love to use this concise syntax for a job as trivial as assigning one integer. I guess I missed something obvious? About Lambdas? Or about ContextMenus??
I tried a Property and also changing the MenueItem but didn't find how persist anything from that lambda..
Update:
Now that I have learned the menu.Show
doesn't block as a ShowDialog
does, I can change my code simply to
mi.Click += (sender, e) => { menuAction( mi) ; };
and
void menuAction(MenuItem choice)
{
//..do my stuff
}
So the Property change I had tried as well was persisted after all but I had used the Property too soon and read the 'outer variable' part of the specs a bit too pessimistically..
Upvotes: 0
Views: 525
Reputation: 21947
You seem to be under the impression that calling Show
on your ContextMenu
will block until the menu is closed.
This is in fact not the case, the showMenu
method will exit right after showing the menu, before the user selects an item, and your choice
local will be thin air at that point.
You must use an instance or otherwise referenced variable to store the selection in.
Typically, you would define a field on the class which contains showMenu
, and reference that field in your lambda.
However, that field will be populated only when the user selects an item, which is not right after you call Show
on the ContextMenu
.
Upvotes: 2