Why a
Panel
control? Wouldn't a
PictureBox
control be more suitable?
Here is a solution for another question that I gave that does what I think that you are trying to do... The solution is for rendering cells (subpanels) without flickering and to enable them to be identified when clicked.
Create a new project and drop this code in... Then run and click away...
1. Form Designer:
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.butAdd = new System.Windows.Forms.Button();
this.butHide = new System.Windows.Forms.Button();
this.butShow = new System.Windows.Forms.Button();
this.Canvas = new System.Windows.Forms.PictureBox();
this.labSelected = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.Canvas)).BeginInit();
this.SuspendLayout();
this.butAdd.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.butAdd.Location = new System.Drawing.Point(676, 6);
this.butAdd.Name = "butAdd";
this.butAdd.Size = new System.Drawing.Size(112, 34);
this.butAdd.TabIndex = 1;
this.butAdd.Text = "ADD";
this.butAdd.UseVisualStyleBackColor = true;
this.butAdd.Click += new System.EventHandler(this.OnAddClick);
this.butHide.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Right)));
this.butHide.Location = new System.Drawing.Point(676, 46);
this.butHide.Name = "butHide";
this.butHide.Size = new System.Drawing.Size(112, 34);
this.butHide.TabIndex = 1;
this.butHide.Text = "HIDE";
this.butHide.UseVisualStyleBackColor = true;
this.butHide.Click += new System.EventHandler(this.OnHideClick);
this.butShow.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Right)));
this.butShow.Location = new System.Drawing.Point(676, 86);
this.butShow.Name = "butShow";
this.butShow.Size = new System.Drawing.Size(112, 34);
this.butShow.TabIndex = 1;
this.butShow.Text = "SHOW";
this.butShow.UseVisualStyleBackColor = true;
this.butShow.Click += new System.EventHandler(this.OnShowClick);
this.Canvas.Anchor = ((System.Windows.Forms.AnchorStyles)
((((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Bottom) |
System.Windows.Forms.AnchorStyles.Left) |
System.Windows.Forms.AnchorStyles.Right)));
this.Canvas.BackColor = System.Drawing.SystemColors.ControlDark;
this.Canvas.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Canvas.Location = new System.Drawing.Point(12, 12);
this.Canvas.Name = "Canvas";
this.Canvas.Size = new System.Drawing.Size(646, 426);
this.Canvas.TabIndex = 2;
this.Canvas.TabStop = false;
this.labSelected.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Right)));
this.labSelected.Location = new System.Drawing.Point(676, 400);
this.labSelected.Name = "labSelected";
this.labSelected.Size = new System.Drawing.Size(121, 38);
this.labSelected.TabIndex = 3;
this.labSelected.Text = "None";
this.labSelected.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Right)));
this.label2.Font = new System.Drawing.Font("Segoe UI", 9F,
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this.label2.Location = new System.Drawing.Point(664, 368);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(133, 32);
this.label2.TabIndex = 4;
this.label2.Text = "Selected Cell:";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.label2);
this.Controls.Add(this.labSelected);
this.Controls.Add(this.Canvas);
this.Controls.Add(this.butShow);
this.Controls.Add(this.butHide);
this.Controls.Add(this.butAdd);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.Canvas)).EndInit();
this.ResumeLayout(false);
}
#endregion
private Button butAdd;
private Button butHide;
private Button butShow;
private PictureBox Canvas;
private Label labSelected;
private Label label2;
}
2. Form code-behind
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Resize += Form1_Resize;
Canvas.Paint += Canvas_Paint;
Canvas.MouseClick += Canvas_MouseClick;
Canvas.SetDoubleBuffered();
Canvas.BackColor = Color.Gray;
Canvas.BorderStyle = BorderStyle.FixedSingle;
Canvas.Cursor = Cursors.Hand;
}
private bool showCells = true;
private record Cell(int Row, int Column, string Text, bool Visible = true);
private readonly List<Cell> cells = new();
private readonly float cellWidth = 50f;
private readonly float cellHeight = 50f;
private readonly Font cellFont = new Font( "Time New Roman", 8, FontStyle.Bold );
private readonly StringFormat cellTextFormat = new StringFormat()
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center
};
private readonly Color cellBackColor = Color.White;
private readonly Color cellForeColor = Color.Black;
private readonly Color cellBorderColor = Color.Black;
private void Form1_Resize(object? sender, EventArgs e)
{
}
private void Canvas_MouseClick(object? sender, MouseEventArgs e)
{
if (showCells)
labSelected.Text =
$@"{Math.Floor(e.X / cellWidth):N0},{Math.Floor(e.Y / cellHeight):N0}";
}
private void Canvas_Paint(object? sender, PaintEventArgs e)
{
Graphics gr = e.Graphics;
foreach (Cell cell in cells)
{
RectangleF rect =
new RectangleF(cell.Column * cellWidth,
cell.Row * cellHeight, cellWidth, cellHeight);
using SolidBrush backBrush = new SolidBrush(cellBackColor);
gr.FillRectangle(backBrush, rect);
if (!showCells)
continue;
using Pen pen = new Pen(cellBorderColor, 1);
pen.Alignment = PenAlignment.Outset;
gr.DrawRectangle(pen, rect);
using SolidBrush foreBrush = new SolidBrush(cellForeColor);
gr.DrawString(cell.Text, cellFont, foreBrush, rect, cellTextFormat);
}
}
private void OnAddClick(object sender, EventArgs e)
{
cells.Clear();
FillCells();
showCells = true;
Canvas.Invalidate();
}
private void OnShowClick(object sender, EventArgs e)
{
if (showCells) return;
showCells = true;
Canvas.Invalidate();
}
private void OnHideClick(object sender, EventArgs e)
{
if (!showCells) return;
showCells = false;
Canvas.Invalidate();
labSelected.Text = "None";
}
void FillCells()
{
int nLabelNum = 10;
for (int j = 0; j < nLabelNum; j++)
for (int i = 0; i < nLabelNum; i++)
cells.Add(new Cell(j, i, $"{i} | {j}"));
}
}
It has 3 buttons, Add, Hide, Show. Press Add to render the clickable grid. The other buttons are self explanatory. There is also a label to display which cell was clicked.
UPDATE
Here is a version that corrects your use of dynamic panels. I've also added a mock paint event to show that the
HostPanel
can be painted behind the child controls (panels). What you want to render is up to you...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeChildPanels();
HostPanel.Paint += OnPaint;
this.Closing += OnClosing;
HostPanel.Invalidate();
}
private void OnPaint(object sender, PaintEventArgs e)
{
_thread = new Thread(() =>
{
Thread.Sleep(500);
HostPanel.Invoke((MethodInvoker)delegate
{
HostPanel.BackColor = _colors[_colorIndex];
_colorIndex = _colorIndex < _colors.Length - 1 ?
_colorIndex + 1 : 0;
});
});
_thread.Start();
}
private Thread _thread;
private Color[] _colors = new Color[]
{
Color.Red,
Color.Green,
Color.Yellow,
Color.Blue,
Color.MediumPurple,
Color.White,
Color.Gray,
};
private int _colorIndex = 0;
private void InitializeChildPanels()
{
int y = 0;
for (int i = 0; i < 5; i++)
{
int x = 0;
for (int j = 0; j < 5; j++)
{
Point point = new Point(x, y);
Panel panel = new Panel()
{
Location = point,
Size = new Size(50, 50),
BackColor = Color.Red,
BorderStyle = BorderStyle.FixedSingle,
Tag = point
};
panel.MouseClick += OnMouseClick;
HostPanel.Controls.Add(panel);
x += 50;
}
y += 50;
}
}
private void OnMouseClick(object sender, MouseEventArgs e)
{
Panel panel = (Panel)sender;
Point point = (Point)panel.Tag;
Debug.WriteLine($"Index: {HostPanel.Controls.IndexOf(panel)} | Location: X:{point.X} Y:{point.Y} was clicked");
}
private void OnClosing(object sender, CancelEventArgs e)
{
_thread.Abort();
_thread = null;
Closing -= OnClosing;
HostPanel.Paint -= OnPaint;
foreach (Panel panel in HostPanel.Controls)
{
panel.MouseClick -= OnMouseClick;
}
}
}
I still prefer the
PictureBox
(first) method.
Enjoy!