检查滚动条可见性

时间:2010-12-31 18:05:56

标签: c# winforms listview scrollbar visibility

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

我有一个带有listView的Windows窗体,如果listview的Vertical Scroll Bar可见,我想抓住resize事件!

2 个答案:

答案 0 :(得分:3)

如果这是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。

答案 1 :(得分:0)

我使用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中的多个显示器时