具有大量控件的假滚动容器

use*_*322 4 c# optimization controls winforms

我正在尝试优化 FlowLayoutPanel 的填充和滚动,但我之前遇到过类似控件的问题,如果它们内部有太多控件,则容器需要很长时间才能填充并准备使用(并且滚动条变得越来越短,您可能对此很熟悉)。

我读过,您可以使用容器矩形可见边界内的控件池,并通过用相应的内容重新填充它们来模拟滚动,就好像它们没有这种优化一样。所以你像往常一样滚动,但人口并不需要那么长的时间。但对于一般情况我该如何实现呢?

我正在使用自定义控件来填充 FlowLayoutPanel 容器,因此我正在寻找一个足够通用的解决方案,可以应用于我的控件和标准 .Net 控件。

TaW*_*TaW 7

显示和滚动性能尝试虚拟分页的充分理由,尽管可以通过Controls.AddControls.AddRange调用和双缓冲容器替换来克服它们。

..但还有另一个问题:任何 Winforms 控件的显示尺寸都限制为 32k 像素。即使您将其放大,也不会显示超出此限制的任何内容。

以下是实施虚拟分页时要做的事情的快速列表:

  • 使用双缓冲FlowLayoutPanel子类来简化布局并使其无闪烁。
  • 关闭AutoSizeAutoScroll
  • VScrollBar在FLP的右侧添加一个并保持Height与FLP的相同
  • 计算您的Height(加) 。我假设您将控件添加到 UC 中,以使事情变得更容易。MarginsUserControl
  • 计算寻呼号码
  • 创建一个List<yourUserControlClass> theUCs
  • 现在创建您的 UC,但仅将它们添加到列表中theUCs
  • 编写一个scrollTo(int ucIndex)函数,清除FLP 的控件并从列表中添加正确的范围。
  • FLP 的代码KeyPreview允许使用键盘滚动。

VScrollBar为的属性设置正确的值,即Minimum, Maximum, Value, SmallChange, LargeChange有点棘手,并且每当调整FLP 大小或在列表中添加删除元素时都必须设置页面大小。

在我的测试中,设置和滚动结果都是瞬时的。从顶部只能看到完整的UC,这对我来说没问题。我在 a 、 a和 a中添加了1000 个带有位图的 UC 。PanelLabelCheckedListBox

以下是我计算设置的方法Maximum

float pageSize =  flowLayoutPanel2.ClientSize.Height / 
                  (uc1.Height + uc1.Margin.Top + uc1.Margin.Bottom);
vScrollBar1.Maximum = (int)( 1f * theUCs.Count / (pageSize)) + 9;
Run Code Online (Sandbox Code Playgroud)

extra是针对 a的理论值和实际值9的奇怪偏移的解决方法。ScrollBarMaximum

如果ValueChanged我写道:

private void vScrollBar1_ValueChanged(object sender, EventArgs e)
{
    int pageSize = flowLayoutPanel1.ClientSize.Height / theUCs.First().Height;
    int v = Math.Min(theUCs.Count, vScrollBar1.Value);

    flowLayoutPanel1.SuspendLayout();
    flowLayoutPanel1.Controls.Clear();
    flowLayoutPanel1.Controls.AddRange(theUCs.Skip( (v- 1) * pageSize)
                                             .Take(pageSize + 1).ToArray());
    flowLayoutPanel1.ResumeLayout();
}
Run Code Online (Sandbox Code Playgroud)

这会滚动到某个项目:

void scrollTo(int item)
{
    int pageSize = flowLayoutPanel1.ClientSize.Height / theUCs.First().Height;
    int p = item / pageSize + 1;
    vScrollBar1.Value = p;
}
Run Code Online (Sandbox Code Playgroud)

为了更平滑的滚动,请使用DoubleBuffered子类:

class DrawFLP : FlowLayoutPanel
{
    public DrawFLP() { DoubleBuffered = true; }
}
Run Code Online (Sandbox Code Playgroud)

这可能有点粗糙,但我希望它能让您走上正确的道路。

在此输入图像描述