65.9K
CodeProject 正在变化。 阅读更多。
Home

了解 .NET 滚动条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (26投票s)

2004年12月28日

3分钟阅读

viewsIcon

155551

downloadIcon

3313

滑块大小、分页和子分页问题。

引言

滚动条表面上看起来很简单,但我最近发现 .NET 实现需要进行一些小的调整才能满足我的需求。 我决定编写一个小测试应用程序来研究滚动条以及不同的属性如何影响滚动条的视觉和功能方面。

滚动条如何工作?

通常需要设置滚动条的三个方面:

  • 滑块,使其反映文档的可见部分,该部分与整个文档成比例,整个文档由整个轨道高度(或宽度,对于水平滚动条)表示。
  • 如何设置滚动条,以便在用户单击轨道时正确地在文档中分页。
  • 如何设置滚动条,以便在用户移动滑块或使用滚动条边缘的箭头按钮时,可以正确显示子页面更改。

这在 .NET 中很容易通过以下属性实现

  • LargeChange 设置可查看的“页面”尺寸。
  • Maximum 设置文档的总尺寸。

设置这两个属性可以调整滚动条,使滑块正确反映与整个文档宽度或高度成比例的可查看“页面”。 以下等式说明了 LargeChangeMaximum 与滑块长度和滚动条长度之间的关系(我在这里使用长度来反映一个维度,宽度或高度)

LargeChange     Thumb Length
-----------  =  ------------  
  Maximum       Track Length

此外,当用户单击轨道时,滚动条的 Value 会更改 LargeChange 值。

子页面滚动

.NET 实现中的假设是,您总是希望按“页面”(LargeChange)滚动。 我遇到一种情况,我不想这样做。 我有一个图像查看器,其中包含图像行,我想要的是 LargeChange 按行滚动,而不是整个可见的“页面”(由多行组成)。 同时,我希望 SmallChange 滚动像素行,以便查看器平滑滚动。 第二个要求意味着我不能这样做

LargeChange=1;       // 1 row
Maximum=numRows;     // total # of rows

因为现在我无法指定一个子行 SmallChange (此属性的类型是 int)。 相反,我应该这样做

SmallChange=1;                // 1 pixel of change
LargeChange=rowHeight;        // height of 1 row
Maximum=numRows * rowHeight   // total height of all rows

但现在我的滑块不再与可见的“页面”成比例! 现在,滑块反映的是一行与整个文档的比率,而不是整个页面与整个文档的比率。 虽然这从功能角度来看是有效的,但视觉方面是错误的。

解决方案

解决方案是将 LargeChange(必须使用它来使滑块设置为适当的大小)与用户单击轨道时 Value 的实际更改分离。 这是通过重写 WndProc 方法并在专门的 VScrollBar(或 HScrollBar)中捕获向上/向下翻页消息来实现的

protected override void WndProc(ref Message m)
{
  if (m.Msg == 8469)
  {
    switch((uint)m.WParam)
    {
      case 2: // page up
        if (this.Value - this.ValLargeChange > 0)
        {
          this.Value-=this.ValLargeChange;
        }
        else
        {
          this.Value=0;
        }
        break;

      case 3: // page down
        if (this.Value+this.LargeChange+this.ValLargeChange < this.Maximum)
        {
          this.Value+=this.ValLargeChange;
        }
        else
        {
          this.Value=this.Maximum - this.LargeChange;
        }
        break;

      default:
        base.WndProc (ref m);
        break;
    }
  }
  else
  {
    base.WndProc (ref m);
  }
}

这控制了默认的滚动条行为,并基于我所需的较大更改(在 ValLargeChange 属性中)更改了 Value

结论

您可以玩演示来查看操作中的差异。 请注意,此代码并不出色,属性名称很笨拙,并且消息值是硬编码的。 显然,它不是生产代码。 正如项目名称所示,这仅仅是对该问题的研究。

© . All rights reserved.