更新面板的子项时出现“闪烁”问题

时间:2009-11-03 06:06:27

标签: c# .net winforms

我有TableLayoutPanel,其中包含标签行。此控件生活在具有渐变背景的表单上。标签定期更新,通常作为整套。更新后,它们会非常缓慢地更新,并且对用户来说非常明显。

我尝试在表单上使用DoubleBuffered,但正如预期的那样,这没有帮助。然后我尝试扩展TableLayoutPanel并设置其DoubleBuffered属性,但这似乎让事情变得更糟。我也试过SuspendLayout()在桌子上,但这也没有任何效果。

我选择了此设置,因为DataGridView不支持透明度...但我真的想找到此设置的替代方案。

Other questions似乎有关系,但我找不到解决问题的方法。

有关如何解决更新问题或可能的替代方案的任何想法?

编辑由于我正在处理要在此表上表示的固定数量的数据,我正在研究直接在绘图处理程序中绘制字符串,而不是使用标签。

2 个答案:

答案 0 :(得分:2)

标签是否停靠(意味着label.Dock = DockStyle.Fill)?

每次label.Text更改之间有多少代码?

我的应用程序具有完全相同的UI。 TableLayoutPanel里面的TableLayoutPanel里面的TableLayoutPanel里面的标签。但没有渐变背景。每个面板和标签都没有边距和填充。每个标签都是码头填充的。首先,我们获得每个标签的所有值。只有在那之后我们才会改变所有标签,但是在单独的线程中。

string[] texts = GetAllLabels();
ownerControl.Invoke(new Action(() =>
{
  for (int i = 0; i < UpdatingControls.Count && i < texts.Count; i++)
  {
    UpdatingControls[i].Text = texts[i];
  }
}));

这减少了(在我们的例子中)眨眼到最小。

答案 1 :(得分:1)

消除闪烁的唯一方法是使用自定义控件(例如面板)的绘制处理程序。我试过的其他方法似乎可以减少闪烁,但没有任何东西可以消除它。

根据我所看到的,标签本身每个都做类似的事情,当他们的数据发生变化时,他们自己就会失效。无法阻止此过程,因此净效果是每个标签的滚动/滞后更新到下一个。这在复杂背景(例如图像)上被放大。

通过使用绘制处理程序并计算每个“行”的边界,我能够为我的应用程序获取相同的表格,并且其背景保持透明。

这不是新颖的代码,但这是为了防止其他人:

private const int RowCount = 10;
private DataTable _table;  // updated elsewhere

private void OnPaint(Object sender, PaintEventArgs e) {
    if (! this.DesignMode) {
        DrawTable(e.Graphics);
    }
}

private void DrawTable(Graphics gfx) {
    SolidBrush brush = new SolidBrush(this.ForeColor);
    for (int rownum = 0; rownum < RowCount; rownum++) {
        RectangleF rect = GetRowBounds(rownum);
        DrawRowNumber(gfx, rect, rownum);

        if (_table.Rows.Count > rownum) {
            DataRow data = _table.Rows[rownum];
            DrawName(gfx, rect, Convert.ToString(data["name"]));
            DrawCount(gfx, rect, Convert.ToSingle(data["count"]));
        }
    }
}

private void DrawRowNumber(Graphics gfx, RectangleF bounds, int place) {
    String str = String.Format("{0}.", (place + 1));
    SolidBrush brush = new SolidBrush(this.ForeColor);
    gfx.DrawString(str, this.Font, brush, bounds.Location);
}

private void DrawName(Graphics gfx, RectangleF bounds, String name) {
    PointF loc = new PointF(80, bounds.Top);
    SolidBrush brush = new SolidBrush(this.ForeColor);
    gfx.DrawString(name, this.Font, brush, loc);
}

private void DrawCount(Graphics gfx, RectangleF bounds, float score) {
    SolidBrush brush = new SolidBrush(this.ForeColor);
    String str = score.ToString("N1");
    SizeF size = gfx.MeasureString(str, this.Font);
    float offset = bounds.Right - size.Width;
    PointF loc = new PointF(offset, bounds.Top);
    gfx.DrawString(str, this.Font, brush, loc);
}

private RectangleF GetRowBounds(int row) {
    if ((row < 0) || (row >= RowCount)) {
        return RectangleF.Empty;
    }

    Rectangle bounds = this.ClientRectangle;
    float height = (float) bounds.Height / (float) RowCount;

    PointF loc = new PointF(bounds.Left, height * row);
    SizeF size = new SizeF(bounds.Width, height);

    return new RectangleF(loc, size);
}