检查滚动条可见性

Posted

技术标签:

【中文标题】检查滚动条可见性【英文标题】:Check Scrollbar Visibility 【发布时间】:2011-06-02 01:51:52 【问题描述】:

有没有办法检查垂直滚动条在某个 ListView 对象上是否可见?

我有一个带有 listView 的 Windows 窗体,如果 listview 的垂直滚动条可见,我想捕捉到 resize 事件!

【问题讨论】:

@thephpdeveloper 我不相信他的意思是 ListView 对象...而是实际的 ListView,将其还原... 【参考方案1】:

如果这是 WPF,则此处为 sample exist,它在解决方案的基础上连接到 ListView.LayoutUpdated

如果这是 WinForms,您可以使用 pinvoke 和 GetWindowLong...

  static public class WndInfo
  
    [DllImport("user32.dll", SetLastError = true)]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    ...
    public static bool IsWindowTopMost(IntPtr Handle)
    
      return (GetWindowLong(Handle, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
    
    ...
  

VB code exists 使用 GetWindowLong 检查是否存在可以移植到 C# 的 ScrollBar。

【讨论】:

@Cloaky - 最好在你的问题中写下尽可能多的细节。您可以点击编辑链接来编辑您的问题 =) 不,您没有...问题中仍然没有任何内容可以说明您在谈论 Windows 窗体。我以为你也在谈论 WPF。 问题是,您真的需要这些信息吗?如果要适合列,最好只使用 ClientRectangle;它总是在滚动条内提供可用区域。【参考方案2】:

我在使用 Winforms 时使用了几种方法,这些方法基于我想从中获取信息的控件类型。这是我的课。

public static class NativeMethods

    const Int32 LVM_FIRST = 0x1000;
    const Int32 LVM_SCROLL = LVM_FIRST + 20;

    [DllImport("user32")]
    static extern IntPtr SendMessage(IntPtr Handle, Int32 msg, IntPtr wParam, IntPtr lParam);


    // offset of window style value
    const int GWL_STYLE = -16;

    // window style constants for scrollbars
    const int WS_VSCROLL = 0x00200000;
    const int WS_HSCROLL = 0x00100000;

    [DllImport("user32.dll", SetLastError = true)]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);


    static ScrollBars GetControlVisibleScrollbars(Control ctl)
    
        int wndStyle = GetWindowLong(ctl.Handle, GWL_STYLE);
        bool hsVisible = (wndStyle & WS_HSCROLL) != 0;
        bool vsVisible = (wndStyle & WS_VSCROLL) != 0;

        if(hsVisible)
            return vsVisible ? ScrollBars.Both : ScrollBars.Horizontal;
        else
            return vsVisible ? ScrollBars.Vertical : ScrollBars.None;
    

    public static ScrollBars GetVisibleScrollbars(this ListView lv)
    
        if(lv is null)
        
            throw new ArgumentNullException(nameof(lv));
        

        return GetControlVisibleScrollbars(lv);
    


    public static ScrollBars GetVisibleScrollbars(this ScrollableControl ctl)
    
        if(ctl is null)
        
            throw new ArgumentNullException(nameof(ctl));
        

        if(ctl.HorizontalScroll.Visible)
            return ctl.VerticalScroll.Visible ? ScrollBars.Both : ScrollBars.Horizontal;
        else
            return ctl.VerticalScroll.Visible ? ScrollBars.Vertical : ScrollBars.None;
    


    private static void ScrollHorizontal(Form form, int pixelsToScroll)
    
        SendMessage(form.Handle, LVM_SCROLL, (IntPtr)pixelsToScroll, IntPtr.Zero);
    

    public static void EnsureVisible(this ListViewItem item, int subItemIndex, int margin=10)
    
        if(item is null)
        
            throw new ArgumentNullException(nameof(item));
        

        if( subItemIndex > item.SubItems.Count - 1)
        
            throw new IndexOutOfRangeException($"ListView item.ListView.Name does not have a SubItem on index subItemIndex");
        

        // scroll to the item row.
        item.EnsureVisible();
        Rectangle bounds = item.SubItems[subItemIndex].Bounds;
        bounds.Width = item.ListView.Columns[subItemIndex].Width;
        ScrollToRectangle(item.ListView,bounds,margin);
    



    private static void ScrollToRectangle(ListView listView, Rectangle bounds, int margin)
    
        int scrollToLeft = bounds.X + bounds.Width + margin;
        if(scrollToLeft > listView.Bounds.Width)
        
            ScrollHorizontal(listView.FindForm(),scrollToLeft - listView.Bounds.Width);
        
        else
        
            int scrollToRight = bounds.X - margin;
            if(scrollToRight < 0)
            
                ScrollHorizontal(listView.FindForm(),scrollToRight);
            
        
    

假设在您的用例中您有一个分隔面板,并且您希望左侧面板足够宽而没有水平滚动条,那么您可以这样做:

var bar= MyListView.GetVisibleScrollbars();
while(bar== ScrollBars.Horizontal || bar== ScrollBars.Both)

    progressPanels.SplitterDistance += 5;
    bar = MyListView.GetVisibleScrollbars();

我并不是说这是最好的方法,我只是说这是一种选择,尤其是在处理不同 DPI 的多台显示器时

【讨论】:

以上是关于检查滚动条可见性的主要内容,如果未能解决你的问题,请参考以下文章

可见性更改时,IFrame 滚动条在 chrome 上消失

当可见性发生变化时,IFrame滚动条会在Chrome上消失

如何使滚动条不可见[重复]

如何隐藏水平滚动条并保持垂直滚动条可见,同时仍然能够水平滚动?

使面板滚动条无效

使滚动条在移动浏览器中可见