W. C. Bastedo
W. C. Bastedo

Reputation: 9

In C# how does one access the elements of an array of control labels created at runtime?

Over the years I've done a significant amount of programming in various forms of BASIC, including Visual Basic. When it comes to C# I'm quite confused. Below is the form load code for a mastermind program I am creating in C#. Everything works, until I try to create my marking routine.

 public void Form1_Load(object sender, EventArgs e)
    {
        //int columns = 14;
        Label[,] board = new Label[5,14];
        for (int i = 0; i < 5; i++)
        {
            for (int j = 0; j < 14; j++)
            {
                board[i,j] = new Label();
                board[i,j].AutoSize = false;
                board[i,j].Size = Dummy.Size;
                board[i,j].BorderStyle = BorderStyle.Fixed3D;
                board[i,j].BackColor = Color.Beige;
                board[i,j].Location = new Point(i * Dummy.Width+2, j * Dummy.Height+2);
                board[i,j].Name = "board" + i.ToString() + "," + j.ToString();
                board[i,j].Width = Dummy.Width - 4;
                board[i,j].Height = Dummy.Height - 4;
                board[i,j].TabIndex = 0;
                //board[i][j].Text = i.ToString() +" "+ j.ToString();
                panel2.Controls.Add(board[i,j]);
                board[i,j].Click += new EventHandler(Label1_Click);
            }        
            P2.Click += new EventHandler(P1_Click);
            P3.Click += new EventHandler(P1_Click);
            P4.Click += new EventHandler(P1_Click);
            P5.Click += new EventHandler(P1_Click);
            P6.Click += new EventHandler(P1_Click);
            P7.Click += new EventHandler(P1_Click);
            P8.Click += new EventHandler(P1_Click);
        }
        int marker = 14;
        int each = 5;
        Label[,] mark = new Label[each,marker];
        // Instantiating all the buttons in the array
        for (int i = 0; i < each; i++)
        {
            for (int j = 0; j < marker; j++)
            {
                mark[i, j] = new Label();
                mark[i, j].AutoSize=false;
                mark[i, j].Size = Minnie.Size;
                mark[i, j].BorderStyle = Minnie.BorderStyle;
                mark[i, j].BackColor = Color.Blue;
                mark[i, j].Left = i * (Minnie.Width+2)+3;
                mark[i, j].Top = j * Dummy.Height+10;
                panel3.Controls.Add(mark[i, j]);
            }
        }
    }

This creates the playing 'holes' for guesses, and smaller marking 'holes' in panels 2 and 3, respectively. The playing part works fine as I have a selection panel that allows the user to choose colors and then 'place' the colors by clicking the board holes array. The various colours are matched by numbers which I append to the .Tag of board elements when they are clicked. The diffculty comes when I try to read the .Tags to assess the guesses for marking. Here is the code that is not working:

    public void button1_Click(object sender, EventArgs e)
    {
        int r;
        for (r=0;r<5;r++) {
            textBox1.Text = textBox1.Text + board[0,r].Tag;
            //board[0, r].BackColor = Color.Azure;
        }
    }

The board[0, r].BackColor = Color.Azure; was an attempt to isolate where the error derives. It generated the same error, so it seems that the button routine knows that 'board' exists but doesn't acknowledge or is unable to access the subscripted elements. The error generated is:

▶ $exception {"Object reference not set to an instance of an object."} System.NullReferenceException

What do I need to do in order to overcome this difficulty?

Thanks in advance,

Cam

Upvotes: 1

Views: 93

Answers (1)

Gabriel Luci
Gabriel Luci

Reputation: 40928

Each variable has a scope: the section of code where that variable is valid. If you define it in a method, then the variable can only be used within that method.

So in this case, if you want to use that variable in multiple methods, you need to declare in a scope that encompasses those methods. In this case, that is your Form1 class - so just inside the declaration of the class, but outside any method.

But you also need to remove the declaration inside Form1_Load too, otherwise you'll end up with two variables with the same name and different scopes. They may have the same name, but they will refer to two different places in memory and not hold the same data. When you use board inside Form1_Load you will refer to the one declared inside that method, and it will be destroyed as soon as the method finishes.

Upvotes: 1

Related Questions