最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Is there a way to reference a picturebox just created and added during runtime? - Stack Overflow

programmeradmin3浏览0评论

Im using Visual Studio Community with the Windows Forms template, and was wondering if there is a way to reference a newly created pcb when created during runtime like shown in code:

for (int i = 0; i <= mapSize - 1 && !foundPos; i++)
{
    for (int j = 0; j <= mapSize - 1 && !foundPos; j++)
    {
        var pcb = new PictureBox();
        pcb.Name = "pcb" + i + "" + j;
        pcb.Margin = new Padding(0);
        pcb.Size = new Size(slotSize, slotSize);
        pcb.Location = new Point(0 + i * slotSize, 0 + j * slotSize);
        if (currMap[i, j] == 5)
            pcb.BackColor = Color.Yellow;
        if (currMap[i, j] == 0)
            pcb.BackColor = Color.White;
        if (currMap[i, j] == 1)
            pcb.BackColor = Color.Gray;
        this.Controls.Add(pcb);

    }
}

this.pcb00.BackColor = Color.Yellow; // A way to reference the pictureboxes just made?

i gave the picturebox a name when i created it and tried using the name of the picturebox like normal.

Im using Visual Studio Community with the Windows Forms template, and was wondering if there is a way to reference a newly created pcb when created during runtime like shown in code:

for (int i = 0; i <= mapSize - 1 && !foundPos; i++)
{
    for (int j = 0; j <= mapSize - 1 && !foundPos; j++)
    {
        var pcb = new PictureBox();
        pcb.Name = "pcb" + i + "" + j;
        pcb.Margin = new Padding(0);
        pcb.Size = new Size(slotSize, slotSize);
        pcb.Location = new Point(0 + i * slotSize, 0 + j * slotSize);
        if (currMap[i, j] == 5)
            pcb.BackColor = Color.Yellow;
        if (currMap[i, j] == 0)
            pcb.BackColor = Color.White;
        if (currMap[i, j] == 1)
            pcb.BackColor = Color.Gray;
        this.Controls.Add(pcb);

    }
}

this.pcb00.BackColor = Color.Yellow; // A way to reference the pictureboxes just made?

i gave the picturebox a name when i created it and tried using the name of the picturebox like normal.

Share Improve this question asked Feb 7 at 12:56 Spell CinSpell Cin 151 silver badge3 bronze badges 2
  • You have to pass instance of the control (PictureBox in this case) as instance of any other class around. The winform designer creates a property for you. Since you need indexing, consider creating property of type which supports indexes, like currMap, e.g. array PictureBox[,] – Sinatr Commented Feb 7 at 13:28
  • To mention: you usually don't layout your Controls like that. You'd use a TableLayoutPanel, add your Controls to its cells, then utilize the Column / Row reference to access the Control from a dedicated collection, or make use of the TableLayoutPanel's dedicated methods, as GetControlFromPosition() (and the opposite, GetPositionFromControl()) etc. You also allow the parent Form to scale as required, without messing up the layout of your Controls – Jimi Commented Feb 7 at 13:36
Add a comment  | 

2 Answers 2

Reset to default 2

You'll need to either keep a reference to the variable created or perform operations on the Controls container it's in to find it later. In my own application I have a custom control, and I keep a dictionary<string, MyCustomControl> that I add the generated controls to for easier access.

See the answers here for information on using either this.Controls.Find() or this.Controls[name] to find the control if needed.

You're doing the right thing by naming the PictureBox controls before adding them to this.Controls. You don't need to do anything else, thanks to the string indexer of the Controls collection, just refer to a control (for example) as Controls["pcb01"] as shown in the working minimal example below.

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        // Set some values so example can compile
        const int mapSize = 3, slotSize = 100;
        bool foundPos = false;
        int[,] currMap = new int[mapSize, mapSize];
        // ========================================

        for (int i = 0; i < mapSize && !foundPos; i++)
        {
            for (int j = 0; j < mapSize && !foundPos; j++)
            {
                var pcb = new PictureBox
                {
                    Name = $"pcb{i}{j}",
                    Size = new Size(slotSize, slotSize),
                    Location = new Point(0 + i * slotSize, 0 + j * slotSize),
                    BackColor = Color.LightBlue,
                };
                pcb.Left += 50;
                pcb.Top += 50;
                // Skip the colors so this example can set them below
                this.Controls.Add(pcb);
                pcb.BorderStyle = BorderStyle.FixedSingle;

                Debug.WriteLine(pcb.Name);
            }
        }
        Controls["pcb00"].BackColor = Color.White;
        Controls["pcb01"].BackColor = Color.Gray;
        Controls["pcb12"].BackColor = Color.Yellow;
    }
}


That said, I agree with Jimi's comment that you might greatly benefit from a TableLayoutPanel.

TableLayoutPanel Minimal Example

public partial class MainForm : Form
{
    TableLayoutPanel currMap;
    public MainForm()
    {
        InitializeComponent();
        const int DIM = 3;
        Padding = new Padding(25);
        currMap = new TableLayoutPanel
        {
            Dock = DockStyle.Fill,
            RowCount = DIM,
            ColumnCount = DIM,
            BackColor = Color.LightBlue,
            Padding = new Padding(2),
        }; 
        Controls.Add(currMap);
        int autoIncrement = 0;
        for (int col = 0; col < DIM; col++)
        {
            currMap.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
            currMap.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
            for (int row = 0; row < DIM; row++)
            {      
                var pcb = new SmartSquare
                {
                    Name = $"pcb{col}{row}",
                    ValueForDemo = autoIncrement++, 
                };
                currMap.Controls.Add(pcb, col, row);
            }
        }
    }
}

In this case, there are at least two answers to the question:

Is there a way to reference a picturebox just created and added during runtime?

currMap.Controls["pcb20"].BackColor = Color.Red;
currMap.GetControlFromPosition(2,1).BackColor = Color.Green;

I would take it a step further and recommend that you inherit PictureBox to make something like SmartSquare, a custom PictureBox that might (for example) know what color it's supposed to be based on the ValueForDemo property.

SmartSquare Minimal Example

class SmartSquare : PictureBox
{
    public SmartSquare() 
    { 
        Margin = new Padding(2);
        Dock = DockStyle.Fill;
        BorderStyle = BorderStyle.FixedSingle;
    }

    public int ValueForDemo
    {
        get => _valueForDemo;
        set
        {
            if (!Equals(_valueForDemo, value))
            {
                _valueForDemo = value;
                switch (_valueForDemo)
                {
                    case 0:
                        BackColor = Color.White;
                        break;
                    case 1:
                        BackColor = Color.Gray;
                        break;
                    case 5:
                        BackColor = Color.Yellow;
                        break;
                    default:
                        BackColor = Color.Transparent;
                        break;
                }
            }
        }
    }
    int _valueForDemo = int.MinValue;
}

SmartSquare Demo

Using your examples of {5, 0, 1}:

发布评论

评论列表(0)

  1. 暂无评论