Toon Casteele
Toon Casteele

Reputation: 2579

How to stop Paint events from stacking up

I'm creating an application to schedule different tasks. These are displayed by drawing rectangles on a panel. This has to be responsive. So I need to draw and invalidate on every size change. When I reach a maximum height of my planning panel it autoscrolls.

The problem is when I grab the scrollbar and start scrolling away for a bit, when I release the scrollbar my whole application and computer freezes.

Most likely this is due to the onpaint event being called on every little scroll and stacking up, leaving the application to hang until they are all done.

Now my question is: How would I be able to fix this? Possibly by keeping the paint event from being called multiple times, but how?

The method called by the paint event:

private void panelPlanning_Paint(object sender, PaintEventArgs e)
    {
        for (int i = 0; i < userList.Count; i++)
        {
            Label temp = new Label();
            temp.Text = userList[i].Text;
            temp.Width = panelUsers.Width;
            temp.Height = 50;
            temp.BorderStyle = BorderStyle.FixedSingle;
            temp.Location = new Point(0, i * 50);
            temp.TextAlign = ContentAlignment.MiddleCenter;
            panelUsers.Controls.Add(temp);

            foreach (FullTask task in taskList)
            {
                if (task.AssignedTo == userList[i].Text && task.StartDate != "" && task.DueDate != "")
                {
                    DateTime start = DateTime.ParseExact(task.StartDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
                    DateTime end = DateTime.ParseExact(task.DueDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
                    Brush brush;
                    if (task.Priority == Enums.priorities[2])
                    {
                        brush = Brushes.Yellow;
                    }
                    else if (task.Priority == Enums.priorities[1])
                    {
                        brush = new SolidBrush(Color.FromArgb(255, 0, 80, 123));
                    }
                    else
                    {
                        brush = Brushes.Red;
                    }

                    panelPlanning.CreateGraphics().FillRectangle(brush, new Rectangle((start.Subtract(dtPickerStart.Value).Days + 1) * labelDaysWidth, i * 50, (end.Subtract(start).Days + 1) * labelDaysWidth, 25));
                }
            }
        }
    }

Upvotes: 2

Views: 2339

Answers (4)

DarkSquirrel42
DarkSquirrel42

Reputation: 10257

as already Described by @LarsTech, don't add controls in the paint event, and use the supplied Graphics object instead of your own ...

If you still face performance problems, consider painting on a bitmap whenever you change something, and only draw that bitmap onto the screen in onPaint

Upvotes: 0

Tigran
Tigran

Reputation: 62266

You have to trace which FullTask actually has to be displayed on the screen. This can be achieved by looking on Control.ClientRectangle and keeping in mind current scroll position.

In this way from the all set of the FullTasks to draw you will get only that subset of tasks that actually visible on the screen, and draw only those ones.

This is a correct way of dealing with drawable artifacts which is implemented in more or less all drawing frameworks 2D or even 3D.

There is also concept of tracing if some element is covered (or part of it is covered) by another element, so it will be "culed", but in your case this doesn't seem to matter.

Pay attention also on fact that you adding controls. Do not do that. If the amount of FullTasks is big, just draw them with Graphics object.

Upvotes: 0

Max
Max

Reputation: 13358

The following line of code should only be executed once:

panelUsers.Controls.Add(temp);

You are constantly adding a new instance of temp to the panelUsers control.

Upvotes: 0

LarsTech
LarsTech

Reputation: 81620

You are adding new Label controls on every single paint event. Don't do this:

      // Label temp = new Label();
      // temp.Text = userList[i].Text;
      // temp.Width = panelUsers.Width;
      // temp.Height = 50;
      // temp.BorderStyle = BorderStyle.FixedSingle;
      // temp.Location = new Point(0, i * 50);
      // temp.TextAlign = ContentAlignment.MiddleCenter;
      // panelUsers.Controls.Add(temp);

Also, use the e.Graphics object supplied by the argument, not CreateGraphics,

Upvotes: 5

Related Questions