1

I am trying to create a dynamically added array of user-controls where each one will have a random color assigned to it to make the user more able to differentiate it from others, but when I do that it produces pattern of colors. It will create 10 of the user-controls with the same color then it will change the color for the next 10, I want each separate one to have a different color.

enter image description here

The code for the user-control:

public partial class EquationBox : UserControl
{
    public EquationBox()
    {
        InitializeComponent();

        this.panel4.BackColor = RandomColor();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.Visible = false;
        this.textBox1.Text = "";
    }

    private Color RandomColor()
    {
        Random rnd = new Random();
        /*KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
        KnownColor randomColorName = names[r.Next(names.Length)];
        Color randomColor = Color.FromKnownColor(randomColorName);
        return randomColor;*/

        Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
        return randomColor;
    }
}

The Code for form1:

    public partial class Form1 : Form
{
    public static EquationBox[] EquationBoxArray = new EquationBox[100];

    public Form1()
    {
        InitializeComponent();

        for (int x = 0; x < 100; x++)
        {
            EquationBoxArray[x] = new EquationBox();
            EquationBoxArray[x].Parent = flowLayoutPanel1;

            EquationBoxArray[x].Visible = false;
        }
    }

    private void add_line_Click(object sender, EventArgs e) //Add Line
    {
          for(int x = 0; x < 100; x++)
          {
              if(!EquationBoxArray[x].Visible)
              {
                  EquationBoxArray[x].Visible = true;
                  EquationBoxArray[x].Refresh();
                  break;
              }
          } 
    }

    private void clear_Click(object sender, EventArgs e) //Clear Lines
    {
        for (int x = 0; x < 100; x++)
        {
            EquationBoxArray[x].Visible = false;
            EquationBoxArray[x].ResetText();
        } 
    }

    private void Form1_SizeChanged(object sender, EventArgs e) //Window Size Changed
    {

    }
}

Thanks in advance, any help would be much appreciated!

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Nicholas Ramsay
  • 465
  • 2
  • 16

5 Answers5

1

The Random class is only a pseudo-random number generator, controlled by the seed parameter in the constructor. To achieve a better distribution of random numbers, try putting the creation of the Random object outside of the loop, or seed it with a different value each time.

For example

public partial class EquationBox
{
    private static Random rnd;

    static EquationBox()
    {
        rnd = new Random();
    }

    public EquationBox()
    {
        this.panel4.BackColor = GetRandomColor();
    }

    private Color GetRandomColor()
    {
        Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
        return randomColor;
    }
}
Daniel Becroft
  • 716
  • 3
  • 19
0

You need to create global Random instance, or use another it constructor https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

Spawn
  • 935
  • 1
  • 13
  • 32
0

Your error comes from creating the Random Number Generator everytime you need a new random colour. The RNG is usually seeded with the current time and because you are creating new ones very quickly the get the same seed.

public partial class EquationBox
{
 static Random rnd = new Random();

 public EquationBox()
 {
    InitializeComponent();

    lock (rnd)
    {
      this.panel4.BackColor = Color.FromArgb(rnd.Next(257), rnd.Next(257), rnd.Next(257));
    }
  }
}

Random.Next is not thread safe, so I have a lock around it. Also it returns a value LESS than the max parameter. So you most likely want to pass 257 instead of 256.

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
0

More the Random to a field, then use it in the RandomColor function, as below.

Random _rnd = new Random();

private Color RandomColor()
{


    Color randomColor = Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256));
    return randomColor;
}

This fixes it because Random uses a seed to initialize the pseudorandom number generator, which is the number of milliseconds since the computer was started. Therefore, if you create more than one Random in the same millisecond, it will start with the same seed.

MineR
  • 2,144
  • 12
  • 18
0

you should only use one instance of Random Class.The problem could be because you are creating new instance of Random every time you call RandomColor . You can move it to another class

public class MyRandom
{
    private  static Random _randColor=new Random();

     private Color GetRandomColor()
     {
       Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
       return randomColor;
     }

}  

and in your user control call it using

public EquationBox()
{
    InitializeComponent();

    this.panel4.BackColor = MyRandom.GetRandomColor();
}
Rohit
  • 10,056
  • 7
  • 50
  • 82