带有很多控件的假滚动容器 [英] Fake-scrolling containers with very many controls

查看:24
本文介绍了带有很多控件的假滚动容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to optimize populating and scrolling a FlowLayoutPanel, but I've had issues with similar controls before, where if they have too many controls inside, it takes a really long while for the container to populate and get ready for use (and the scroller gets shorter and shorter, you might be familiar with that).

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

I've read that you can use a pool of just the controls within visible boundaries of the container rectangle and simulate scrolling by repopulating them with corresponding contents, as if they would be without this optimization. So you scroll as usual but the population doesn't take nearly as long. But how do I implement that for a general case?

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

I'm using custom controls to populate the FlowLayoutPanel container, so I'm looking for a generic enough solution that can be applied to both my control and the standard .Net controls.

推荐答案

显示和滚动性能是尝试虚拟分页的好理由,尽管可以通过替换 控件来克服这些问题.使用 Controls.AddRange 调用和双缓冲容器添加..

Display and scrolling performance are good reasons to try a virtual paging, although they can be overcome by replacing the Controls.Add with a Controls.AddRange call and a double-buffered container..

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

..but there is another: Any Winforms control is limited to 32k pixels in its display dimensions. Even if you make it larger nothing will be displayed beyond this limit.

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

Here is a quick list of things to do, when implementing virtual paging:

  • 使用双缓冲 FlowLayoutPanel 子类来简化布局并使其无闪烁.
  • 关闭AutoSizeAutoScroll
  • 在 FLP 的右侧添加一个 VScrollBar 并保持其 Height 与 FLP 的相同
  • 计算UserControlHeight(加上Margins).我假设您将控件添加到 UC 中,以简化操作.
  • 计算分页数
  • 创建一个ListUCs
  • 现在创建您的 UC,但仅将它们添加到列表 theUCs
  • 编写一个 scrollTo(int ucIndex) 函数,该函数清除 FLP 的控件并从列表中添加正确的范围.
  • 代码 KeyPreview 用于 FLP 以允许使用键盘滚动.
  • Use a double-buffered FlowLayoutPanel subclass to simplify the layout and make it flicker-free.
  • Turn off AutoSize and AutoScroll
  • Add a VScrollBar to the right of the FLP and keep its Height the same as the FLP's
  • Calculate the Height (plus Margins) of your UserControl. I assume you add your control wrapped up in a UC, to make things easier.
  • Calculate the paging numbers
  • Create a List<yourUserControlClass> theUCs
  • Now create your UCs but add them only to the list theUCs
  • Code a scrollTo(int ucIndex) function, which clears the FLP's controls and adds the right range from the list.
  • code KeyPreview for the FLP to allow scrolling with the keyboard.

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

Setting the right values for the VScrollBar's properties, i.e. Minimum, Maximum, Value, SmallChange, LargeChange is a little tricky and setting the page size must be done whenever the FLP is resized or elements are added to or removed from the list.

在我的测试中,设置和滚动结果都是即时的.从顶部只能看到完整 UC,这对我来说很好.我在 PanelLabelCheckedListBox 中添加了 1000 个带有位图的 UC.

In my test the setting up and the scrolling results were instantaneous. Only complete UCs are visible from the top, which is fine with me. I have added 1000 UCs with a bitmap in a Panel, a Label and a CheckedListBox.

这里是我如何计算 Maximum 的设置:

Here is how I calculate the setting for Maximum:

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

额外的 9 是针对 ScrollBar 的理论和实际 Maximum 值的奇怪偏移的一种解决方法.

The extra 9 is a workaround for the quirky offset of a ScrollBar's theoretical and actual Maximum values.

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

这会滚动到某个项目:

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

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

For even smoother scrolling use a DoubleBuffered subclass:

class DrawFLP : FlowLayoutPanel
{
    public DrawFLP() { DoubleBuffered = true; }
}

这可能有点粗糙,但我希望它能让你走上正轨.

This is probably a bit rough at the edges, but I hope it'll get you on the right track.

这篇关于带有很多控件的假滚动容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆