C# - 具有动态数据输入的动态按钮

C# - Dynamic buttons with dynamic data-entering

我这里有点问题。

我正在尝试使用可变数据创建动态点击事件。

for(int i = 0; i < data.Devices.Length; i++)
{
    Button _button = new Button();
    _button.Size = new Size(100, 15);
    _button.Text = data.Devices[i].Alias;
    _button.Name = "textbox" + i.ToString();
    _button.Location = new Point(x,y);
    x += 110;

    if(x > 1850)
    {
        y += 50;
        x = 10;
    }

    if (data.Devices[i].OnlineState == "Online")
    {
        _button.BackColor = Color.Green;
    }
    else
    {
        _button.BackColor = Color.Red;
    }

     _button.Click += (Sender, args) =>
     {
         MessageBox.Show(data.Devices[i].Alias);
     };

     Controls.Add(_button);
 }

这里的想法是我将创建按钮直到完成列表的长度(这些对象的列表和位置各不相同)。

我正在寻找的是制作一堆按钮,当你点击按钮时,你会打开另一个屏幕,其中包含一些附加到该对象的统计信息。

由于数据变化很大,因此无法对每个场景进行硬编码,但我希望做与您在 Android 中可以做的相同的事情,见下文。

for (int i = 1; i <= 20; i++) {
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.MATCH_PARENT,
        LinearLayout.LayoutParams.WRAP_CONTENT);

    Button btn = new Button(this);
    btn.setId(i);
    final int id_ = btn.getId();
    btn.setText("button " + id_);
    btn.setBackgroundColor(Color.rgb(70, 80, 90));
    linear.addView(btn, params);
    btn1 = ((Button) findViewById(id_));

    btn1.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            Toast.makeText(view.getContext(), "Button clicked index = " + id_, Toast.LENGTH_SHORT).show();
    }
});

有什么办法可以实现吗?

亲切的问候。

我认为您遇到的问题是关于 closures

在您的示例中,您添加的事件处理程序带有一个引用变量 i 的委托,该变量会更改每个循环迭代。因此,当事件处理程序实际执行时(单击按钮时)i 超出范围。

你可以这样做:

private void Form1_Shown(object sender, EventArgs e)
{
    var items = new[] { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };

    for (int i = 0; i < items.Length; i++)
    {
        var btn = new Button
        {
            Text = $"Button {i + 1}",
            Tag = items[i]
        };

        btn.Click += (object obj, EventArgs args) 
            =>
            {
                MessageBox.Show($"Hello.  {((Button)obj).Tag}");
            };

        flowLayoutPanel1.Controls.Add(btn);
    }
}

在您的情况下 - 按钮的标签可以设置为 data.Devices[i] - 换句话说,它不必是字符串,它可以是对象。

我首先使用 创建按钮并将它们放置在屏幕上。

for (int i = 0; i < data.Devices.Length; i++){
Button _button = new Button();
_button.Size = new System.Drawing.Size(100, 55);
_button.Text = data.Devices[i].Alias;
_button.Name = "dynamicButton";
_button.FlatStyle = FlatStyle.Flat;
_button.Tag =   data.Devices[i].Alias + "|" + 
                data.Devices[i].DeviceId + "|" + 
                data.Devices[i].LastSeen + "|" + 
                data.Devices[i].OnlineState + "|" + 
                data.Devices[i].Description + "|" + 
                data.Devices[i].RemotecontrolId; 

_button.Location = new System.Drawing.Point(x, y);
x += 110;
if (x > 1850)
{
    y += 60;
    x = 30;
}
_button.Click += new EventHandler(bt_click);
Controls.Add(_button);
}

然后使用onclick事件。

protected void bt_click(object sender, EventArgs e)
    {
        Button btn = sender as Button;
        String[] information = btn.Tag.ToString().Split('|');
        String present = "Namn: " + information[0]
                        + "\nDeviceID: " + information[1]
                        + "\nSenast uppe: " + information[2]
                        + "\nStatus: " + information[3]
                        + "\nEmail: " + information[4]
                        + "\nTW-ID: " + information[5];
        MessageBox.Show(present);
        //DO THE THINGS WITH THE INFORMATION                
    }

然后卸载所有内容并最终更新设备的状态。

for (int i = 0; i < 10; i++)
        {
            foreach (Control item in Controls.OfType<Control>())
            {
                if (item.Name == "dynamicButton")
                {
                    Controls.Remove(item);                        
                }
            }
        }

出于某种原因,我必须将那个东西循环几次,因为它不会将它们全部删除,而是以某种模式删除它们。 (每次只取隔一个)

我循环了 10 次以取得良好效果。

它完全符合我的要求,新设备会自动添加,删除的设备也会同样快速地消失。