C# 如何为动态生成的按钮绑定独立点击事件 无需手动逐个编写?
问题原因
你遇到的是C#中闭包的变量捕获问题:lambda表达式捕获的是循环变量i本身,而非每次迭代时i的瞬时值。整个循环过程中只有一个i变量,当循环结束后i的值已经变为3,所有按钮的点击事件触发时,读取的都是这个最终的i值,所以只会输出Klick - 3。
解决方案1:循环内创建临时变量保存迭代值
在绑定事件的循环内部,新增一个局部临时变量接收当前i的值,每次循环迭代都会创建独立的临时变量,lambda捕获各自的临时变量就不会出现值覆盖的问题:
public static void Main(string[] args){ Form form = new Form(); form.Location = new System.Drawing.Point(0,0); form.Width = 300; form.Height = 300; List<Button> buttons = new List<Button>(); for(int i = 0; i < 3; i++) { buttons.Add(new Button()); buttons[i].Text = $"Button - {i}"; buttons[i].Location = new System.Drawing.Point(0,i*40); form.Controls.Add(buttons[i]); } for(int i = 0; i < 3; i++) { // 新增临时变量,每次迭代都会创建独立的temp变量 int temp = i; buttons[i].Click += (s,e) => { Console.WriteLine($"Klick - {temp}"); }; } Application.Run(form); }
该方案不需要额外判断,性能和单独绑定事件完全一致。
解决方案2:利用按钮的Tag属性存储标识
你也可以在创建按钮时,把对应的索引直接存到按钮的Tag属性里,点击事件触发时从sender中取出对应的值即可,这种方式更灵活,适合需要传递更多自定义参数的场景:
public static void Main(string[] args){ Form form = new Form(); form.Location = new System.Drawing.Point(0,0); form.Width = 300; form.Height = 300; for(int i = 0; i < 3; i++) { Button btn = new Button(); btn.Text = $"Button - {i}"; btn.Location = new System.Drawing.Point(0,i*40); // 把当前索引存到Tag属性 btn.Tag = i; btn.Click += (s,e) => { // 从触发事件的按钮中取出Tag值 int index = (int)((Button)s).Tag; Console.WriteLine($"Klick - {index}"); }; form.Controls.Add(btn); } Application.Run(form); }
该方案甚至可以省去单独存储按钮列表的步骤,也不需要多分支判断,触发时直接取对应控件的存储值即可,执行效率很高。
内容的提问来源于stack exchange,提问作者Gubbel
相关产品推荐
相关产品推荐

