C# 如何动态创建按钮并向其添加事件?

C# 如何动态创建按钮并向其添加事件?,c#,arrays,visual-studio,events,button,C#,Arrays,Visual Studio,Events,Button,我有一组按钮和一组标签: 标签[]标签=新标签[10]; 按钮[],但=新按钮[10] 单击另一个按钮时,我希望从数组中动态创建新按钮和新标签,同时我还希望but[I]更改标签的tex[I]: private void button1_Click(object sender, EventArgs e) { labels[i] = new Label(); labels[i].Location = new System.Drawing.Point(

我有一组按钮和一组标签:

标签[]标签=新标签[10];
按钮[],但=新按钮[10]

单击另一个按钮时,我希望从数组中动态创建新按钮和新标签,同时我还希望but[I]更改标签的tex[I]:

    private void button1_Click(object sender, EventArgs e)
    {
        labels[i] = new Label();
        labels[i].Location = new System.Drawing.Point(0, 15+a);
        labels[i].Parent = panel1;
        labels[i].Text = "Sample text";
        labels[i].Size = new System.Drawing.Size(155, 51);
        labels[i].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        a = labels[i].Height + labels[i].Top;

        but[i] = new Button();
        but[i].Text = "-";
        but[i].Location = new System.Drawing.Point(0, labels[i].Height + labels[i].Top);
        but[i].Parent = panel1;
        but[i].Size = new System.Drawing.Size(155, 10);
        but[i].Click += new System.EventHandler(but_Click);
        i++;
    }
    private void but[i]_Click(object sender, EventArgs e)
    {
        labels[i].Text = "Changed Text";
    }

但显然我不能将数组放入事件处理程序中,那么我应该如何做呢?

我想这是自我解释:

public void SomeMehthod()
{
    Button btn1 = new Button();
    Button btn2 = new Button();
    Button btn3 = new Button();

    // Your button-array
    Button[] btns = new Button[]
    {
        btn1,
        btn2,
        btn3
    };

    foreach(Button btn in btns)
    {
        // For each button setup the same method to fire on click
        btn.Click += new EventHandler(ButtonClicked);
    }
}

private void ButtonClicked(Object sender, EventArgs e)
{
    // This will fire on any button from the array
    // You can switch on the name, or location or anything else
    switch((sender as Button).Name)
    {
        case "btn1":
            // Do something
            break;
        case "btn2":
            // Do something
            break;
        case "btn3":
            // Do something
            break;
    }
}
或者如果您的阵列可以全局访问:

Button[] btns = new Button[5];
Label[] lbls = new Label[5];

private void ButtonClicked(Object sender, EventArgs e)
{
    Button clicked = sender as Button;
    int indexOfButton = btns.ToList().IndexOf(clicked);

    // ..IndexOf() returns -1 if nothign is found
    if(indexOfButton > 0)
    {
        lbls[indexOfButton].DoWhatYouWant...
    }
}

您可以将数组索引作为标记属性添加到按钮中,然后在中将其拉出,但单击

所以,加上

but[i].Tag = i;
到按钮创建。然后更改事件处理程序:

private void but_Click(object sender, EventArgs e)
{
    int buttonIndex = (int)((Button)sender).Tag;
    labels[buttonIndex].Text = "Changed Text";
}
或者将事件处理程序内联:

but[i].Click += (s,e) => { label[i].Text = "Changed Text"; }
或使用标记属性的其他选项,添加:

but[i].Tag = label[i];

...

private void but_Click(object sender, EventArgs e)
{
    Label label = (Label)((Button)sender).Tag;
    label.Text = "Changed Text";
}

这种方法的优点是,在初始创建控件后,不依赖于保持数组同步。

一种方法是使方法返回一个处理程序,而不是一个处理程序:

private EventHandler but_Click(int i)
{
    return (s, e) => labels[i].Text = "Changed Text";
}
然后像这样使用它:

but[i].Click += but_Click(i);
或内联执行:

but[i].Click += (s, ea) => labels[i].Text = "Changed Text";
这两种方法中的任何一种都是一些编译器魔法,可以捕获
i
变量。这与此等效(这也是一种有效的方法,如果详细的话):


哇,真是太棒了,“但是我点击”甚至没有想到这样的事情。然而,这至少在c#中是不可能的。对于本主题,您使用的是WPF或WinForms是什么?是否只是关于如何动态触发事件的
class MyWrapper {
    private int i;
    public MyWrapper(int i) {
        this.i = i;
    }
    public void TheHandler(object sender, EventArgs e) {
        // TODO: capture the object that owns `labels` also, or this won't work.
        labels[i].Text = "Changed Text";
    }
}

//call with
but[i].Click += new EventHandler(new MyWrapper(i).TheHandler);