2

我正在创建一个应用程序来安排不同的任务。这些通过在面板上绘制矩形来显示。这必须是响应式的。所以我需要在每次尺寸变化时绘制并使其无效。当我达到规划面板的最大高度时,它会自动滚动。

问题是当我抓住滚动条并开始滚动一点时,当我释放滚动条时,我的整个应用程序和计算机都会冻结。

这很可能是由于每次滚动和堆叠都会调用 onpaint 事件,导致应用程序挂起,直到它们全部完成。

现在我的问题是:我将如何解决这个问题?可能是通过防止绘制事件被多次调用,但是如何?

绘制事件调用的方法:

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));
                }
            }
        }
    }
4

4 回答 4

5

您正在为每个绘制事件添加新的标签控件。不要这样做:

      // 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);

此外,使用参数提供的 e.Graphics 对象,而不是 CreateGraphics,

于 2013-04-09T14:27:20.373 回答
0

您必须跟踪FullTask实际上必须在屏幕上显示的内容。这可以通过查看 Control.ClientRectangle并记住当前滚动位置来实现。

这样,从所有FullTasks要绘制的集合中,您将仅获得在屏幕上实际可见的任务子集,并且仅绘制那些

这是处理在或多或少所有绘图框架 2D 甚至 3D 中实现的可绘制工件的正确方法。

如果某个元素被另一个元素覆盖(或部分元素被覆盖),也有跟踪的概念,因此它将被“剔除”,但在您的情况下,这似乎无关紧要。

还要注意您添加控件的事实。不要那样做。如果 FullTask​​ 的数量很大,就用Graphics对象来绘制它们。

于 2013-04-09T14:29:02.490 回答
0

以下代码行应该只执行一次:

panelUsers.Controls.Add(temp);

您不断地temppanelUsers control.

于 2013-04-09T14:33:40.397 回答
0

正如@LarsTech 已经描述的那样,不要在绘制事件中添加控件,并使用提供的 Graphics 对象而不是您自己的...

如果您仍然面临性能问题,请考虑在更改某些内容时在位图上绘制,并且仅在 onPaint 中将该位图绘制到屏幕上

于 2013-04-09T14:45:17.943 回答