سؤال

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));
                }
            }
        }
    }
هل كانت مفيدة؟

المحلول

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,

نصائح أخرى

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.

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.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top