如何强制垂直滚动条始终可以从WinForms中的AutoScroll中看到?

时间:2011-12-31 21:24:17

标签: winforms scrollbars autoscroll

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

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

所以它就像一个混合的AutoScroll。我已经尝试过使用VScrollBars,但我无法弄清楚将它们放在哪里以使其工作。

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

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

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

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

5 个答案:

答案 0 :(得分:8)

C#版本的competent_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);
    }
}

答案 1 :(得分: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

答案 2 :(得分:2)

对我有用的是覆盖CreateParams来电和启用WS_VSCROLL风格。

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

AutoScroll逻辑现在将调整滚动边界,而不会隐藏滚动条。

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

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