That said, there's a major problem with that code at the outset. NEVER call
CreateGraphics
. The way GDI+ drawing on controls should ALWAYS work is like this:
- Store the data that represents the drawing in one or more fields.
- Handle the
Paint
event of the control you want to draw on and use the Graphics
object provided to draw using the data in those fields.
- When you want to change the drawing, modify the data in those fields and call the
Invalidate
method of the control you want to draw on.
The
Invalidate
method tells the control to raise a
Paint
event, so the drawing will get updated based on the new data.
The reason that you need to handle the
Paint
event is that GDI+ drawing gets erased and repainted each time that event is raised. If you call
CreateGraphics
and draw once, that drawing will likely get erased on the next
Paint
event and those events happen regularly.
Note that, while it may be simpler to call
Invalidate
with no arguments, you should generally invalidated the smallest area possible to include the area(s) that have (or may have) changed in the drawing. That's because, while the entire drawing gets performed each time, only the pixels in the invalidated area get repainted because it's the actual repainting that is the slow part. When you see a control flickering, that's because it is being repainted in its entirety too often.
Here's a simple example of drawing boxes on a form:
private readonly List<Rectangle> boxes = new();
private Point? startPoint = null;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
startPoint = e.Location;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (this.startPoint.HasValue)
{
var startPoint = this.startPoint.Value;
var endPoint = e.Location;
var box = new Rectangle(Math.Min(startPoint.X, endPoint.X),
Math.Min(startPoint.Y, endPoint.Y),
Math.Abs(startPoint.X - endPoint.X),
Math.Abs(startPoint.Y - endPoint.Y));
boxes.Add(box);
var invalidationBox = new Rectangle(box.X,
box.Y,
box.Width + 1,
box.Height + 1);
Invalidate(invalidationBox);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (var box in boxes)
{
e.Graphics.DrawRectangle(Pens.Black, box);
}
}