简体   繁体   English

如何使用动态创建的按钮和文本框

[英]How to use buttons and textbox created dynamically

i made a program that create many dynamic panel on button "ADD".我制作了一个程序,可以在“添加”按钮上创建许多动态面板。 The thing is that the name of the dynamic panel that have been created is by this way:问题是已经创建的动态面板的名称是这样的:

pArr[counter].Name = "panel" + (panel0.Controls.Count + 1);

And so on, so i guess the 5th panel would be named "panel5" if I'm right.依此类推,所以我猜如果我是对的,第 5 个面板将被命名为“panel5”。

I added some buttons and a Textbox in these dynamically created panels.我在这些动态创建的面板中添加了一些按钮和一个文本框。 I don't understand how to use them.我不明白如何使用它们。 I have read a lot of posts in here about it but as its the first time I'm working with this kind of dynamic panels, its hard for me to understand.我在这里阅读了很多关于它的帖子,但作为我第一次使用这种动态面板,我很难理解。 I found a lot of examples that seems to answer the question but I'm still confused about the names, how to controls buttons and/or textbox.我发现了很多似乎可以回答问题的示例,但我仍然对名称、如何控制按钮和/或文本框感到困惑。

Per example, how will I set an Event from a button clicked from the 7th panel?例如,我将如何通过从第 7 个面板单击的按钮设置事件? It is complicated.这很复杂。

This is my code:这是我的代码:

private void btnAdd_Click(object sender, EventArgs e)
    {
        Color color = ColorTranslator.FromHtml("#f0f0f0");
        Color color2 = ColorTranslator.FromHtml("#4285f4");
        System.Random R = new System.Random();
        Panel p = new Panel();
        Label lbl = new Label();
        TextBox text = new TextBox();
        Button btn = new Button();
        Button btn2 = new Button();
        Button btn3 = new Button();

        int x = 100;
        int y = 10;

        int x2 = 300;
        int y2 = 10;

        int x3 = 380;
        int y3 = 10;

        int x4 = 20;
        int y4 = 13;

        int x5 = 500;
        int y5 = 10;

        int counter = 0;
        Panel[] pArr = new Panel[25];
        pArr[counter] = p;
        
        pArr[counter].Name = "panel" + (panel0.Controls.Count + 1);
        pArr[counter].BackColor = color;
        pArr[counter].Size = new Size(panel0.ClientSize.Width, 40);
        pArr[counter].BorderStyle = BorderStyle.Fixed3D;           
        pArr[counter].Dock = DockStyle.Top;

        lbl.Text = "Name";
        lbl.ForeColor = color2;
        lbl.Font = new Font("Verdana", lbl.Font.Size);
        lbl.Size = new Size(75, 20);
        lbl.Location = new Point(x4, y4);
        pArr[counter].Controls.Add(lbl);

        text.Name = "txtBox" + (panel0.Controls.Count + 1);
        text.Size = new Size(120, 20);
        text.Location = new Point(x, y);
        pArr[counter].Controls.Add(text);

        btn.Name = "btnStart" + (panel0.Controls.Count + 1);
        btn.Text = "Start";
        btn.Font = new Font("Verdana", btn2.Font.Size);
        btn.ForeColor = color2;
        btn.Size = new Size(75, 20);
        btn.Location = new Point(x2, y2);
        pArr[counter].Controls.Add(btn);

        btn2.Name = "btnStop" + (panel0.Controls.Count + 1);
        btn2.Text = "Stop";
        btn2.Font = new Font("Verdana", btn2.Font.Size);
        btn2.ForeColor = color2;
        btn2.Size = new Size(75, 20);
        btn2.Location = new Point(x3, y3);
        pArr[counter].Controls.Add(btn2);

        btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
        btn3.Text = "Close";
        btn3.Font = new Font("Verdana", btn3.Font.Size);
        btn3.ForeColor = color2;            
        btn3.Size = new Size(75, 20);
        btn3.Location = new Point(x5, y5);
        pArr[counter].Controls.Add(btn3);

        panel0.Controls.Add(pArr[counter]);
        panel0.AutoScroll = false;
        panel0.HorizontalScroll.Enabled = false;
        panel0.HorizontalScroll.Visible = false;
        panel0.HorizontalScroll.Maximum = 0;
        panel0.AutoScroll = true;

        counter++;
                    
    }

Can someone explain me how to control panels/buttons/textbox?有人可以解释我如何控制面板/按钮/文本框吗?

pArr needs to be a member of the class, not a local variable. pArr需要是 class 的成员,而不是局部变量。 Then you can simply access pArr with an index like any other array.然后,您可以像任何其他数组一样简单地使用索引访问pArr

The panel doesn't even need a name.面板甚至不需要名称。 Names are only useful in the Visual Studio designer so that it can generate the .Designer.cs file with a variable name.名称仅在 Visual Studio 设计器中有用,以便它可以生成具有变量名称的.Designer.cs文件。

As for the events, just add an event handler with btn.Click += OnStartClick;至于事件,只需使用btn.Click += OnStartClick; as you would do for a button normally.就像您通常对按钮所做的那样。 In the function declaration, you will get object sender which identifies the button.在 function 声明中,您将获得标识按钮的object sender You can then use Array.IndexOf() MSDN to get the index.然后,您可以使用Array.IndexOf() MSDN来获取索引。

private void OnStartClick(object sender, EventArgs e)
{
    var index = Array.IndexOf((TextBox) sender);
    ...
}

Hokay, so on a comment elsewhere you said you want to好吧,所以在你说你想要的其他地方发表评论

MessageBox.Show("Button name pressed: " + buttonName + " panel position number: " + panelPositionNb) MessageBox.Show("按下的按钮名称:" + buttonName + " 面板 position 编号:" + panelPositionNb)

It means minimally you can have a code that looks like: (the second to last line is new)这意味着您至少可以拥有如下代码:(倒数第二行是新的)

    btn.Name = "btnStart" + (panel0.Controls.Count + 1);
    btn.Text = "Start";
    btn.Font = new Font("Verdana", btn2.Font.Size);
    btn.ForeColor = color2;
    btn.Size = new Size(75, 20);
    btn.Location = new Point(x2, y2);

    btn.Click += (s, e) => MessageBox.Show($"Button name pressed: {btn.Name}");

    pArr[counter].Controls.Add(btn);

Taking this apart:把这个分开:

btn.Click += (s, e) => MessageBox.Show($"Button name pressed: {btn.Name}");
  • .Click is the event of the button. .Click是按钮的事件。 An event is simply a "list of methods that have a particular signature", and when you say += you add a method to the "list of methods that shall be called when the event is raised".事件只是“具有特定签名的方法列表”,当您说+=时,您将一个方法添加到“引发事件时应调用的方法列表”。 There's no defined order;没有明确的顺序; you can add multiple different methods and they will be called, but not necessarily in any particular sequence.您可以添加多个不同的方法,它们将被调用,但不一定以任何特定的顺序。 Click has a type of EventHandler which sets out the number and type of arguments any method must have in order to qualify as an handler for any event that is shaped like an EventHandler Click有一个EventHandler类型,它列出了任何方法必须具有的 arguments 的数量和类型,以便有资格成为任何形状像 EventHandler 的事件的处理程序

  • += we've covered; +=我们已经介绍过; if there is an event on the left, then the thing on the right must be a method with a particular signature (dictated by the event signature) ie in the case of a button your method on the right must be shaped like an EventHandler which means it must have a first argument of type object and a second argument of type EventArgs .如果左边有一个事件,那么右边的东西必须是一个具有特定签名的方法(由事件签名决定),即在按钮的情况下,您右边的方法必须像EventHandler一样形状,这意味着它必须具有object类型的第一个参数和EventArgs类型的第二个参数。 Your btnAdd_Click is an example of a method that conforms to those rules您的btnAdd_Click是符合这些规则的方法的示例

  • (s, e) is a method signature header. (s, e)是方法签名 header。 Specifically it's a mini method that we call a lambda.具体来说,这是一种我们称之为 lambda 的迷你方法。 The compiler looks at the event signature and knows that the first thing has to be object and the second has to be EventArgs ;编译器查看事件签名并知道第一件事必须是object ,第二件事必须是EventArgs you only have to give names - the compiler will fill in the types .您只需给出名称- 编译器将填写类型 Actually because we don't even use the names of the arguments in the method code, we could just write (_, _) (in .net core+; framework might complain about duplicate names) here which means "no name; throw it away".. But if we did use the variable in the lambda method we'd have to give it a name.实际上,因为我们甚至没有在方法代码中使用 arguments 的名称,我们可以只写(_, _) (在 .net core+;框架可能会抱怨重复名称)这里表示“没有名称;扔掉它” .. 但是如果我们确实在 lambda 方法中使用了变量,我们就必须给它一个名字。 We could give them types too: (object s, EventArgs e) and it starts to look a lot like a normal method if we do;我们也可以给它们类型: (object s, EventArgs e)如果我们这样做,它开始看起来很像普通方法; we don't add these because mostly we don't need to;我们不添加这些,因为大多数情况下我们不需要; the compiler can usually figure them out on its own编译器通常可以自己找出它们

  • => is the thing that separates a lambda method signature from the body =>是将 lambda 方法签名与正文分开的东西

  • MessageBox.Show($"Button name pressed: {btn.Name}") is the body of the method; MessageBox.Show($"Button name pressed: {btn.Name}")是方法的主体; the thing that will happen when the button is clicked.单击按钮时将发生的事情。

Doing a panel close one:做一个面板关闭一个:

    btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
    btn3.Text = "Close";
    btn3.Font = new Font("Verdana", btn3.Font.Size);
    btn3.ForeColor = color2;            
    btn3.Size = new Size(75, 20);
    btn3.Location = new Point(x5, y5);

    var pnl = pArr[counter];
    btn3.Click += (s,e) => pnl.Visible = false;

    pnl.Controls.Add(btn3);

Here we take the panel and capture it into a temporary variable.在这里,我们将面板捕获到一个临时变量中。 There are specific reasons for doing this, and it doesn't exactly apply to your code as written but I'm assuming at some point you'll upgrade this to use a loop;这样做有特定的原因,它并不完全适用于您编写的代码,但我假设您会在某个时候升级它以使用循环; if we just did pArr[counter].Visible C# would take the resting value of counter as it was after all the looping is done, and hide that panel.. Any button would either cause an error, because counter would be off the end of the panels array, or some other wrong panel would hide.如果我们只是做了pArr[counter].Visible C# 将在所有循环完成后采用counter的剩余值,并隐藏面板。任何按钮都会导致错误,因为counter会在结束面板数组,或者其他一些错误的面板会隐藏。


We don't have to use these mini-methods (lambdas);我们不必使用这些小方法(lambdas); we can pass this data around another way if you like..如果您愿意,我们可以通过其他方式传递这些数据..

Taking the example of the panel hide, because it's actually doing something interesting with the UI.以面板隐藏为例,因为它实际上对 UI 做了一些有趣的事情。 Let's have a method that hides a panel that it finds in the Tag of the control in the sender :让我们有一个方法来隐藏它在sender控件的Tag中找到的面板:

private void HidePanelInTag(object sender, EventArgs e){

  //get the sender as a button; we will only ever attach this code to buttons that have a Panel in their Tag
  var b = sender as Button;
  
  //get the Tag from the button and cast it to a panel
  var p = b.Tag as Panel;

  p.Visible = false;
}

Now we can tweak the loop that is creating the btn3 close buttons:现在我们可以调整创建btn3关闭按钮的循环:

    btn3.Name = "btnClose" + (panel0.Controls.Count + 1);
    btn3.Text = "Close";
    btn3.Font = new Font("Verdana", btn3.Font.Size);
    btn3.ForeColor = color2;            
    btn3.Size = new Size(75, 20);
    btn3.Location = new Point(x5, y5);

    btn3.Tag = pArr[counter];
    btn3.Click += HidePanelInTag;

    pnl.Controls.Add(btn3);

We've stored the panel in the Tag - this varies for every button, a different Panel.我们已将面板存储在标签中 - 每个按钮、不同的面板都会有所不同。 The event handler attachment looks simpler too, because whereas a lambda has a full method (header, and body) defined on the line it is encountered, in more old fashioned terms the method definition is separated from its use:事件处理程序附件看起来也更简单,因为虽然 lambda 在遇到的行上定义了完整的方法(标题和正文),但在更老式的术语中,方法定义与其使用分开:

btn3.Click += HidePanelInTag;

Remember before we said += separates an event on the left, from a method on the right;记得之前我们说过+=将左侧的事件与右侧的方法分开; so long as the method on the right obeys the signature of the event, we're allowed to "add it to the list of methods that are called when the event is raised".只要右边的方法遵守事件的签名,我们就可以“将其添加到引发事件时调用的方法列表中”。

When the button is clicked, HidePanelInTag is called.单击按钮时,将调用HidePanelInTag Windows Forms automatically puts the control that is raising the event (the button) into the object sender argument. Windows Forms 自动将引发事件(按钮)的控件放入object sender参数中。 That's how we retrieve the Panel to hide;这就是我们检索要隐藏的面板的方式; every button has a different Panel in its tag.每个按钮的标签中都有一个不同的面板。 If you click the 25th button, the sender is the 25th button, and the Tag is the 25th panel如果点击第25个按钮, sender就是第25个按钮, Tag就是第25个面板


End of the day there are loads of ways to skin this cat.一天结束时,有很多方法可以给这只猫剥皮。 For example you don't have to store a panel in a button's Tag.. You could even do some crazy like this:例如,您不必将面板存储在按钮的标签中。您甚至可以像这样疯狂地做一些事情:

btn3.Click += (s, e) => {
  var b = s as Button;
  var pname = b.Name.Replace("btnClose", "panel");
  var p = panel0.Controls[pname];
  p.Visible = false;
};

Get the button name, change it to be what the panels name is, find the panel by name, hide it... All in a multi-line lambda.获取按钮名称,将其更改为面板名称,按名称查找面板,将其隐藏...全部在多行 lambda 中。 That's kinda nasty, just treat it "for educational purposes" - ultimately all these buttons you make end up stored in tree of controls (your form has a penal that has panels that have buttons..) that can be searched, so "name" does have a use.. But we probably wouldn't use it for this approach.这有点讨厌,只是“出于教育目的”对待它 - 最终您制作的所有这些按钮最终都存储在控件树中(您的表单有一个带有按钮的面板的惩罚......)可以搜索,所以“名称”确实有用.. 但我们可能不会将它用于这种方法。

The main take-away from this is that just like setting the name, the text, the position etc dynamically you also need to wire up the click events dynamically.主要的收获是,就像动态设置名称、文本、position 等一样,您还需要动态连接点击事件。 That's done using event_name_here += event_handler_method_name_without_parentheses_here ;这是使用event_name_here += event_handler_method_name_without_parentheses_here的; in this regard methods aren't really any different from data variables in the way they're passed around by name在这方面,方法在通过名称传递的方式上与数据变量并没有什么不同

Basically this is my code:基本上这是我的代码:

public partial class UserControl2 : UserControl
{       
    Color color;
    Color color2;
    System.Random r;
    Panel p;
    private int counter = 0;
    Panel[] pArr = new Panel[25];
    Label lbl;
    TextBox pnlTxtBox;
    Button pnlBtnStart;
    Button pnlBtnStop;
    Button pnlBtnClose;

    
    
    //Label
    private int x = 20;
    private int y = 13;

    //TextBox
    private int x2 = 100;
    private int y2 = 10;

    //Button Start       
    private int x3 = 300;
    private int y3 = 10;

    //Button Stop        
    private int x4 = 380;
    private int y4 = 10;

    //Button Close
    private int x5 = 500;
    private int y5 = 10;

    public UserControl2()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        color = ColorTranslator.FromHtml("#f0f0f0");
        color2 = ColorTranslator.FromHtml("#4285f4");
        r = new System.Random();
        p = new Panel();
        lbl = new Label();
        pnlTxtBox = new TextBox();
        pnlBtnStart = new Button();
        pnlBtnStop = new Button();
        pnlBtnClose = new Button();

        pArr[counter] = p;

        pArr[counter].Name = "panel" + (panel0.Controls.Count + 1);
        pArr[counter].BackColor = color;
        pArr[counter].Size = new Size(panel0.ClientSize.Width, 40);
        pArr[counter].BorderStyle = BorderStyle.Fixed3D;
        pArr[counter].Dock = DockStyle.Top;

        lbl.Text = "Name";
        lbl.ForeColor = color2;
        lbl.Font = new Font("Verdana", lbl.Font.Size);
        lbl.Size = new Size(75, 20);
        lbl.Location = new Point(x, y);
        pArr[counter].Controls.Add(lbl);
        
        pnlTxtBox.Name = "txtBox" + (counter);
        pnlTxtBox.Size = new Size(120, 20);
        pnlTxtBox.Location = new Point(x2, y2);
        pArr[counter].Controls.Add(pnlTxtBox);

        pnlBtnStart.Name = "btnStart" + (panel0.Controls.Count + 1);
        pnlBtnStart.Text = "Start";
        pnlBtnStart.Font = new Font("Verdana", pnlBtnStart.Font.Size);
        pnlBtnStart.ForeColor = color2;
        pnlBtnStart.Size = new Size(75, 20);
        pnlBtnStart.Location = new Point(x3, y3);
        pnlBtnStart.Click += new EventHandler(pnlBtnStart_Click);       
        pArr[counter].Controls.Add(pnlBtnStart);

        pnlBtnStop.Name = "btnStop" + (panel0.Controls.Count + 1);
        pnlBtnStop.Text = "Stop";
        pnlBtnStop.Font = new Font("Verdana", pnlBtnStop.Font.Size);
        pnlBtnStop.ForeColor = color2;
        pnlBtnStop.Size = new Size(75, 20);
        pnlBtnStop.Location = new Point(x4, y4);
        pArr[counter].Controls.Add(pnlBtnStop);

        pnlBtnClose.Name = "btnClose" + (panel0.Controls.Count + 1);
        pnlBtnClose.Text = "Close";
        pnlBtnClose.Font = new Font("Verdana", pnlBtnClose.Font.Size);
        pnlBtnClose.ForeColor = color2;
        pnlBtnClose.Size = new Size(75, 20);
        pnlBtnClose.Location = new Point(x5, y5);
        pnlBtnClose.Click += new EventHandler(pnlBtnClose_Click);
        pArr[counter].Controls.Add(pnlBtnClose);

        panel0.Controls.Add(pArr[counter]);
        panel0.AutoScroll = false;
        panel0.HorizontalScroll.Enabled = false;
        panel0.HorizontalScroll.Visible = false;
        panel0.HorizontalScroll.Maximum = 0;
        panel0.AutoScroll = true;           
      
        counter++;                        
    }

    void pnlBtnStart_Click(object sender, EventArgs ex)
    {
        pnlBtnStart = sender as Button;
        //var pnlName = pnlBtnStart.Name.Replace("btnStart", "panel");
        var pnlTxtBoxName = pnlTxtBox.Name.Replace("txtBox", "panel");              
        var p = panel0.Controls[pnlTxtBoxName];
        String name = pnlTxtBox.Text;
        MessageBox.Show(name);

    }

    void pnlBtnClose_Click(object sender, EventArgs ex)
    {
        pnlBtnClose = sender as Button;
        var pnlName = pnlBtnClose.Name.Replace("btnClose", "panel");           
        var p = panel0.Controls[pnlName];
        p.Visible = false;
    }
}

} }

I can close the panel(Thank you for this) but when i try to get the "value" from the pnlTxtBox, it seem that i can't identify properly the "textbox" i really need.我可以关闭面板(谢谢),但是当我尝试从 pnlTxtBox 获取“值”时,似乎无法正确识别我真正需要的“文本框”。 It only give me the TextBox.Text of the last created panel.它只给我最后创建的面板的 TextBox.Text。 I will join a pic for you to see the result.我会加入一张照片让你看看结果。

Result of my code我的代码的结果

Give this a go:给这个 go:

public partial class UserControl2 : UserControl
{       
    public UserControl2()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {

        var color = ColorTranslator.FromHtml("#f0f0f0");
        var color2 = ColorTranslator.FromHtml("#4285f4");
        var r = new System.Random();
        var p = new Panel();
        var lbl = new Label();
        var pnlTxtBox = new TextBox();
        var pnlBtnStart = new Button();
        var pnlBtnStop = new Button();
        var pnlBtnClose = new Button();

        p.Name = "panel" + (panel0.Controls.Count + 1);
        p.BackColor = color;
        p.Size = new Size(panel0.ClientSize.Width, 40);
        p.BorderStyle = BorderStyle.Fixed3D;
        p.Dock = DockStyle.Top;

        lbl.Text = "Name";
        lbl.ForeColor = color2;
        lbl.Font = new Font("Verdana", lbl.Font.Size);
        lbl.Size = new Size(75, 20);
        lbl.Location = new Point(20, 13);
        p.Controls.Add(lbl);
        
        pnlTxtBox.Name = "txtBox";
        pnlTxtBox.Size = new Size(120, 20);
        pnlTxtBox.Location = new Point(100, 10);
        p.Controls.Add(pnlTxtBox);

        pnlBtnStart.Name = "btnStart";
        pnlBtnStart.Text = "Start";
        pnlBtnStart.Font = new Font("Verdana", pnlBtnStart.Font.Size);
        pnlBtnStart.ForeColor = color2;
        pnlBtnStart.Size = new Size(75, 20);
        pnlBtnStart.Location = new Point(300, 10);
        pnlBtnStart.Click += (s,e) => StartWasClicked(pnlTxtBox);       
        p.Controls.Add(pnlBtnStart);

        pnlBtnStop.Name = "btnStop";
        pnlBtnStop.Text = "Stop";
        pnlBtnStop.Font = new Font("Verdana", pnlBtnStop.Font.Size);
        pnlBtnStop.ForeColor = color2;
        pnlBtnStop.Size = new Size(75, 20);
        pnlBtnStop.Location = new Point(380, 10);
        p.Controls.Add(pnlBtnStop);

        pnlBtnClose.Name = "btnClose";
        pnlBtnClose.Text = "Close";
        pnlBtnClose.Font = new Font("Verdana", pnlBtnClose.Font.Size);
        pnlBtnClose.ForeColor = color2;
        pnlBtnClose.Size = new Size(75, 20);
        pnlBtnClose.Location = new Point(500, 10);
        pnlBtnClose.Click += (s,e) => CloseWasClicked(p);
        p.Controls.Add(pnlBtnClose);

        panel0.Controls.Add(p);
        panel0.AutoScroll = false;
        panel0.HorizontalScroll.Enabled = false;
        panel0.HorizontalScroll.Visible = false;
        panel0.HorizontalScroll.Maximum = 0;
        panel0.AutoScroll = true;           
      
               
    }

    void StartWasClicked(TextBox tb){
        MessageBox.Show(tb.Text);
    }

    void CloseWasClicked(Panel p){
        p.Visible = false;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM