C# 使列表中的按钮向方法发送唯一数据

C# 使列表中的按钮向方法发送唯一数据,c#,winforms,list,button,methods,C#,Winforms,List,Button,Methods,我制作了一个应用程序,可以在网格中放置按钮,用户可以指定游戏场地的大小。 我在列表中创建按钮,指定一些数据,如背景图像、大小和位置。然后,我需要以某种方式使不同的按钮执行不同的代码。我想我可以用一种方法来实现这一点(如果没有任何好的编程方法来创建方法的话),如果我可以让按钮向方法发送一条唯一的信息来识别按下了哪个按钮 public void buttonplacer() { int nbrofbtns = Form2.puzzlesize * Form2.puzz

我制作了一个应用程序,可以在网格中放置按钮,用户可以指定游戏场地的大小。 我在列表中创建按钮,指定一些数据,如背景图像、大小和位置。然后,我需要以某种方式使不同的按钮执行不同的代码。我想我可以用一种方法来实现这一点(如果没有任何好的编程方法来创建方法的话),如果我可以让按钮向方法发送一条唯一的信息来识别按下了哪个按钮

    public void buttonplacer()
    {
        int nbrofbtns = Form2.puzzlesize * Form2.puzzlesize;



        List<Button> btnslist = new List<Button>();
        for (int i = 0; i < nbrofbtns; i++)
        {

            Button newButton = new Button();
            btnslist.Add(newButton);
            this.Controls.Add(newButton);

            newButton.Name = "btn" + i.ToString();
            newButton.Width = btnsidelength;
            newButton.Height = btnsidelength;
            newButton.Top = btnsidelength * Convert.ToInt32(Math.Floor(Convert.ToDouble(i / Form2.puzzlesize)));
            newButton.Left = btnsidelength * Convert.ToInt32(Math.Floor(Convert.ToDouble(i)) - Math.Floor((Convert.ToDouble(i)) / (Form2.puzzlesize)) * (Form2.puzzlesize));
            newButton.BackgroundImage = Lights_out_.Properties.Resources.LightsOutBlack;




            newButton.Click += new EventHandler(Any_Button_Click);
        }
    }
    void Any_Button_Click(object sender, EventArgs e)
    {

    }
public void按钮宏()
{
int nbroftns=Form2.puzzlesize*Form2.puzzlesize;
List btnslist=新列表();
对于(int i=0;i
(如果你想知道我在做一个叫做“灯光熄灭”的游戏)
提前谢谢

Any\u Button\u Click
方法接收一个对象发送器,即被单击的按钮。您只需将其强制转换为
按钮

void Any_Button_Click(object sender, EventArgs e)
{
    Button b = (Button)sender;
    // do stuff here
}
您可以使用按钮的
位置
属性来确定它在游戏板上的位置,也可以使用
标记
属性为按钮指定任意对象,并在初始化时选择任何信息,如下所示:

button.Tag = "someHelpfulString";
button.Tag = new Tuple<int, int>(xpos, ypos);
button.Tag = new ButtonInfoObject(foo, bar, baz);
或者像这样:

button.Tag = "someHelpfulString";
button.Tag = new Tuple<int, int>(xpos, ypos);
button.Tag = new ButtonInfoObject(foo, bar, baz);

(这里由您定义ButtonInfoObject类。)

使用sender对象获取按下按钮的名称:

void Any_Button_Click(object sender, EventArgs e)
{
     switch ((sender as Button).Name)
     {
         case "btn0":
             //...
             break;
         case "btn1":
             //...
             break;
         //...
     }
}

作为其他答案的替代,特别是为了在某种程度上解决“以编程方式创建方法的好方法”这一部分,有一部分C#语言称为。为了让长话短说,你可以按照以下思路写一些东西:

newButton.Click += (s, e) =>
{
    //here you have access to all variables accessible in current scope,
    //including "newButton" and "i";
    //you could, for example, call some method passing "i" as an argument
    //or just put that method's code inside this block
};
这种方法唯一的缺点是,如果您计划在以后某个时候注销处理程序,则需要格外小心(请参阅或以供参考)

编辑

正如我在评论中指出的那样,我忽略了一个事实,
I
在整个
for
循环的范围内,因此在lambda中使用它几乎毫无意义(所有处理程序都将使用它的最终值)。为了使其行为符合预期,只需在循环中定义一个变量,使其在每次迭代结束时超出范围,并为每个处理程序单独存储:

var btnNo = i;
newButton.Click += (s, e) =>
{
    //use "btnNo" instead of "i"
    //you can still safely use "newButton" reference
    //since it's defined inside the loop
}

由于您的按钮具有唯一的名称,也许您可以检查发件人的名称以确定它是什么按钮?或其坐标?将按钮放置在具有正确行数/列数的动态设置表格布局面板中。在按钮处理程序中,将
sender
投射回按钮,并使用确定其网格位置。您还可以使用获取网格中特定位置的其他按钮的引用。我不认为使用
开关
是可能的,因为正如OP所述,拼图大小是不同的。不,这就像为所有按钮创建一个单独的方法,并说您不能有一个大于X的游戏场<代码>开关?真正地不……但是,
i
是否会在该事件注册和事件触发之间进行更改,为所有按钮保留其最终值?(我对闭包有点生疏,如果我错了,很抱歉。)幸运的是它不会。请参阅上述MSDN页面的“Lambda表达式中的变量范围”部分。摘录:“变量(…)存储在lambda表达式中使用…”。我刚刚对此进行了快速测试,我的假设是正确的。我添加了10个按钮,每个按钮都有一个lambda Click处理程序,该处理程序显示一个值为I的MessageBox,无论我单击了哪个按钮,它都是10。@adv12感谢您指出它。我通常使用
foreach
循环,并在其中定义所有必要的变量,因此它没有引起我的注意。好吧,你的意思是b,从技术上讲是按钮,或者至少它有所有的信息?因此,我可以像第一个示例一样,通过b.tag.ToString()检索标记?然后如何设置实际按钮的buttonproberies?在这种情况下,我想改变按钮的背景图像为黑色或白色,这取决于最初的颜色。我可以通过变量检查背景图像,但如何更改按钮??(sry表示双注释)是的,
b
是按钮,您可以通过
b.tag.ToString()
检索标记。要更改背景图像,只需说
b.BackgroundImage=