【发布时间】:2011-05-18 13:10:13
【问题描述】:
我搜索了万维网,但没有找到正确的答案。
在我的 Windows 窗体应用程序中,我想更改属于 FlowLayoutPanel 的滚动条的宽度。
滚动条是“自动”添加的,因为流布局面板的内容比表单大。
从我在网上找到的内容来看,这似乎很棘手。
有什么解决办法吗?
干杯!
【问题讨论】:
标签: .net vb.net winforms controls scrollbar
我搜索了万维网,但没有找到正确的答案。
在我的 Windows 窗体应用程序中,我想更改属于 FlowLayoutPanel 的滚动条的宽度。
滚动条是“自动”添加的,因为流布局面板的内容比表单大。
从我在网上找到的内容来看,这似乎很棘手。
有什么解决办法吗?
干杯!
【问题讨论】:
标签: .net vb.net winforms controls scrollbar
不,无法更改显示在单个控件上的滚动条的宽度(尽管有一个系统范围的设置会影响所有所有滚动条应用程序)。
丑陋的事实是,低级滚动条控件远比看起来复杂。基本上,FlowLayoutPanel 上的滚动条是由 Windows 本身(而不是 .NET Framework)绘制的,因为为后台控件设置了WS_HSCROLL 和/或WS_VSCROLL 窗口样式。 FlowLayoutPanel 不提供任何工具来更改或修改这些内置滚动条的绘制方式。与 WinForms 中其他更高级的修改不同,我们无法将此类消息发送到控件的窗口过程。更糟糕的是,滚动条是在FlowLayoutPanel 的非客户区绘制的,这意味着我们不能只覆盖它的Paint 事件并自己处理滚动条的绘制。
不幸的是,如果您真的想自定义滚动条,您将不得不隐藏内置滚动条并滚动自己的滚动条。不过,这并不像听起来那么难,如果你愿意的话。 CodeProject 上的This article 提供了一个很好的演练,用于创建您自己的可换肤滚动条作为用户控件,并将其用作您选择的容器控件中的替代品。
【讨论】:
Cody Gray's answer 100% 正确,但我想添加更多关于该主题的参考资料。
Windows 窗体创建滚动条的方式是使用window styles WS_HSCROLL 和WS_VSCROLL。这些样式分别负责为给定的HWND 启用水平和垂直滚动条。 HWND 是 "window" 的本机资源句柄,在 .NET 术语中对应于 Control。
从 Windows API 的角度考虑,我们必须在创建 HWND 时设置窗口样式。这是通过调用CreateWindow、CreateWindowEx 或SetWindowLong 来完成的。当然,我们可能会开始考虑使用P/Invoke 来帮助我们,但这将是一个相当大的负担,因为这意味着我们需要从头开始重新实现 Windows 窗体。
幸运的是,Windows 窗体公开了一个属性 CreateParams,可以重写该属性以指定确切的窗口样式以及其他 Control 创建参数。该属性反过来被 .NET 框架使用,因此它可以在 Control 被实例化时创建具有适当样式的 HWND。
为滚动条替换 Windows API 功能实际上比看起来简单;然而,这并不明显(无论如何,对我来说,我不得不筛选 .NET 源代码才能找到答案)。为此,我们必须选择合适的Control 来继承以创建我们自己的自定义ScrollableControl。如果我们观察System.Windows.Forms.ScrollableControl 的源代码,我们会看到使用了以下样式:
CreateParams cp = base.CreateParams;
if (HScroll || HorizontalScroll.Visible) {
cp.Style |= NativeMethods.WS_HSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_HSCROLL);
}
if (VScroll || VerticalScroll.Visible) {
cp.Style |= NativeMethods.WS_VSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_VSCROLL);
}
所以,简而言之,当我们从ScrollableControl 扩展时,会根据其内部逻辑启用原生的水平和垂直滚动条。我们可以访问ScrollableControl的窗口句柄,然后调用SetWindowLong来隐藏滚动条;但是,我们需要跟踪ScrollableControl 与 Windows API 交互的所有位置。事实上,有一个内部函数Control.UpdateStylesCore() 会根据是否显示滚动条来调用。此功能有效地重新应用了上面的 windows 样式,最好不要与之抗争。避开 Windows API 并直接从Control 扩展将是一种更简洁的方法。然后我们可以提供我们想要的任何 API。
这意味着我们将考虑重新实现:
或者,一种简单的方法可能是创建一个新的UserControl。这将允许我们使用 Visual Studio 设计器来简化配置我们的滚动条按钮和轨道。
无论采用哪种方式,都需要了解ScrollableControl 在内部是如何工作的,以便提供舒适的用户体验。
【讨论】:
这对于 C# 以及与 Cody Gray https://stackoverflow.com/a/4326046/4342139 发表在已接受答案中的文章有关。我会直接在那里发表评论,但我对此没有声誉。
如果您像我一样并遵循 Cody Gray 的回答中的文章,那么要隐藏滚动条,您将使用内面板和外面板。这不是最佳解决方案,坦率地说是“奇怪和hacky”。我偶然发现了水平滚动条的类似问题并设法找到了解决方案,同样的事情也适用于垂直滚动。这是一种不那么 hacky 的方式(但不是很多),可以通过以下代码实现:
panel1.AutoScroll = false;
panel1.VerticalScroll.Maximum = 0;
panel1.VerticalScroll.Visible = false;
panel1.HorizontalScroll.Maximum = 0;
panel1.HorizontalScroll.Visible = false;
panel1.AutoScroll = true;
注意:从上面的代码中选择垂直或水平或两者。 将 AutoScroll 设置为 false 然后设置为 true 非常重要,否则设置不会应用或 AutoScroll 被禁用。 将垂直/水平滚动最大值设置为 0 似乎是唯一需要的,但将 Visible 设置为 false 似乎并没有伤害它(似乎根本不起作用,但也许我错过了一些东西)。
【讨论】: