12

将 VS2010 和 .NET 4.0 与 C# 和 WinForms 一起使用:

我总是希望一个垂直滚动条为我的面板显示为禁用的滚动条(当不需要它时,当它可以使用时启用一个滚动条。

所以它就像一个混合 AutoScroll。我尝试过使用 VScrollBars,但我不知道将它们放置在哪里才能完成这项工作。

本质上,我有一个用户控件,它充当控件的“文档”,它的大小会发生变化,因此在使用自动滚动时它可以完美地工作。当用户控件不适合并且用户可以将其向上移动时,会出现滚动条。

它本质上就像一个网络浏览器。但是,重绘控件需要很长时间(它的表单具有许多字段和按钮等在面板内的网格中的组内:P

所以无论如何,当自动滚动启用垂直滚动条时,重绘窗口需要一段时间。我想始终如上所示显示垂直滚动条(具有启用/禁用功能)。

如果有人有帮助,我已经阅读了很多关于自动滚动主题的帖子,但没有人问我在问什么,我无法提出解决方案。

4

6 回答 6

9

C# 版本的 Competitive_Tech 的回答

using System.Runtime.InteropServices; 

public class MyUserControl : UserControl
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);

    private enum ScrollBarDirection
    {
        SB_HORZ = 0,
        SB_VERT = 1,
        SB_CTL = 2,
        SB_BOTH = 3
    }

    public MyUserControl()
    {
        InitializeComponent();
        ShowScrollBar(this.Handle, (int) ScrollBarDirection.SB_VERT, true);
    }
}
于 2014-10-09T12:11:37.160 回答
4

您可以使用面板的自动滚动功能,您只需向它发送一条 windows 消息以显示垂直滚动条:

<DllImport("user32.dll")> _
Public Shared Function ShowScrollBar(ByVal hWnd As System.IntPtr, ByVal wBar As Integer, ByVal bShow As Boolean) As Boolean
End Function

Private Const SB_VERT As Integer = 1


Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ShowScrollBar(Panel1.Handle, SB_VERT, True)
End Sub

滚动条将被显示并看起来好像可以滚动,但在它真正准备好滚动之前它不会做任何事情。如果禁用它,它不会自动重新启用,因此这可能是最好的方法。

此外,为了提高调整大小时的性能,您可以在更新前调用面板上的SuspendLayout并在完成后调用ResumeLayout

于 2011-12-31T21:47:21.620 回答
3

对我CreateParams有用的是覆盖调用并启用WS_VSCROLL样式。

public class VerticalFlowPanel : FlowLayoutPanel
{
    protected override CreateParams CreateParams
    {
        get
        {
            var cp = base.CreateParams;
            cp.Style |= 0x00200000; // WS_VSCROLL
            return cp;
        }
    }
}

逻辑现在将AutoScroll调整滚动范围,而无需隐藏滚动条。

于 2016-08-17T22:05:26.440 回答
1

这就是为我解决这个问题的方法。我的情况是,我有一个面板夹在另外三个面板之间,在任何方向上都没有自由度。我需要这个面板足够大,以至于整个结构都超出了我的 1920x1080 屏幕。解决方案其实很简单。对于需要滚动条的面板,将 AutoScroll 属性设置为 true。然后,在最右边的位置(右下位置)添加另一个控件。我选择的控件是一个标签,我使它不可见....仅此而已。现在我的面板占据了它的限制区域,但我可以滚动到我需要的大小并将其用于我需要的大小。如果您只需要水平滚动条,请在左侧添加不可见控件,垂直仅在底部下方。

面板的实际大小是您在显示时限制它的大小,但虚拟大小由不可见控件决定。

于 2016-08-11T23:11:11.233 回答
0

多年来,BradJ法令的答案对我有用。现在我需要显示禁用的滚动条外观。但是我没有找到正确的方法……所以这是我的解决方法

下面的代码只是在真正的滚动条的位置绘制禁用的滚动条。

垂直流面板


编码

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

public class VerticalFlowPanel : FlowLayoutPanel
{
    public VerticalFlowPanel() 
    {
        AutoScroll = true;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        var width = Width;
        var height = Height;

        var vsWidth = SystemInformation.VerticalScrollBarWidth;
        var vsHeight = SystemInformation.VerticalScrollBarArrowHeight;

        var left = width - vsWidth;

        var sbUpper = new Rectangle(left, 0, vsWidth, height / 2);
        var sbLower = new Rectangle(left, sbUpper.Height, vsWidth, height - sbUpper.Height);
        var arUp    = new Rectangle(left, 0, vsWidth, vsHeight);
        var arDown  = new Rectangle(left, height - vsHeight, vsWidth, vsHeight);

        ScrollBarRenderer.DrawUpperVerticalTrack(e.Graphics, sbUpper, ScrollBarState.Disabled);
        ScrollBarRenderer.DrawLowerVerticalTrack(e.Graphics, sbLower, ScrollBarState.Disabled);

        ScrollBarRenderer.DrawArrowButton(e.Graphics, arUp, ScrollBarArrowButtonState.UpDisabled);
        ScrollBarRenderer.DrawArrowButton(e.Graphics, arDown, ScrollBarArrowButtonState.DownDisabled);
    }

    // Necessary to avoid visual artifacts
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);

        var width = Width;
        var height = Height;

        var vsWidth = SystemInformation.VerticalScrollBarWidth;

        var scrollBounds = new Rectangle(width - vsWidth, 0, vsWidth, height);

        Invalidate(scrollBounds);
    }
}

笔记

这不是最好的解决方案。但这比将我的漏洞解决方案迁移到 WPF 更容易......</p>

于 2021-09-13T14:38:21.320 回答
0

每当 Panel 的内置滚动条不可见时,此代码将绘制一个禁用的垂直滚动条。代码假设

AutoScroll = true;
AutoSize   = false;

以下代码是速度优化的。它在 OnPaint() 中做的尽可能少。

从 Panel 派生一个类。添加这些成员变量:

// NOTE: static variables are not thread safe. 
// But as we have only one GUI thread this does not matter.
static IntPtr mh_ScrollTheme   = IntPtr.Zero;
static int    ms32_ScrollWidth = SystemInformation.VerticalScrollBarWidth;

Win32.RECT mk_ScrollTop;
Win32.RECT mk_ScrollBot;   // coordinates of top scrollbar button
Win32.RECT mk_ScrollShaft; // coordinates of bottom scrollbar button

然后覆盖 OnSizeChanged:

protected override void OnSizeChanged(EventArgs e)
{
    base.OnSizeChanged(e);

    Win32.RECT k_ScrollBar = new Win32.RECT(ClientRectangle);
    k_ScrollBar.Left = k_ScrollBar.Right - ms32_ScrollWidth;

    mk_ScrollTop   = new Win32.RECT(k_ScrollBar);
    mk_ScrollBot   = new Win32.RECT(k_ScrollBar);
    mk_ScrollShaft = new Win32.RECT(k_ScrollBar);

    int s32_Upper = k_ScrollBar.Top    + ms32_ScrollWidth;
    int s32_Lower = k_ScrollBar.Bottom - ms32_ScrollWidth;

    mk_ScrollTop  .Bottom = s32_Upper;
    mk_ScrollBot  .Top    = s32_Lower;
    mk_ScrollShaft.Top    = s32_Upper;
    mk_ScrollShaft.Bottom = s32_Lower;
}

并在需要时绘制滚动条:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    if (VScroll)
        return; // The 'real' scrollbar is visible
            
    if (mh_ScrollTheme == IntPtr.Zero)
        mh_ScrollTheme = Win32.OpenThemeData(Handle, "SCROLLBAR");

    if (mh_ScrollTheme == IntPtr.Zero)
        return; // The user has disabled themes

    // Draw the disabled vertical scrollbar.
    IntPtr h_DC = e.Graphics.GetHdc();

    // Draw shaft
    const int SBP_UPPERTRACKVERT = 7;
    const int SCRBS_DISABLED     = 4;
    Win32.DrawThemeBackground(mh_ScrollTheme, h_DC, SBP_UPPERTRACKVERT, SCRBS_DISABLED, ref mk_ScrollShaft, IntPtr.Zero);

    // Draw top button
    const int SBP_ARROWBTN       = 1;
    const int ABS_UPDISABLED     = 4;
    Win32.DrawThemeBackground(mh_ScrollTheme, h_DC, SBP_ARROWBTN, ABS_UPDISABLED,   ref mk_ScrollTop,  IntPtr.Zero);

    // Draw lower button
    const int ABS_DOWNDISABLED   = 8;
    Win32.DrawThemeBackground(mh_ScrollTheme, h_DC, SBP_ARROWBTN, ABS_DOWNDISABLED, ref mk_ScrollBot,  IntPtr.Zero);

    e.Graphics.ReleaseHdc(h_DC);
}
于 2020-08-18T21:35:22.650 回答