C# ListView禁用水平滚动条

12

有没有办法在ListView中防止水平滚动条的出现?我希望当需要时显示垂直滚动条,但是永远不要显示水平滚动条。

我想这可能与WndProc有关吗?

谢谢

6个回答

9

有一种更简单的方法可以消除下方滚动条并显示垂直滚动条。它包括确保标题和如果没有标题,则行的宽度为listview.Width - 4,如果显示垂直滚动条,则为listview.Width - Scrollbar.Width - 4;

以下代码演示了如何实现:

lv.Columns[0].Width = lv.Width - 4 - SystemInformation.VerticalScrollBarWidth;

这确实是比所选答案更清晰的方法,也是问题的根本原因。ListView的列需要更小。谢谢你的提示,对我很有帮助。 - Tobias
3
如果您使用复选框行,我认为这不会起作用。此外,我认为固定值不好,因为其他窗口设计可能会使用不同的尺寸。最后但并非最不重要的是,这不是一个更干净的方法。如果您不想要滚动条,则应该隐藏/禁用它,而不是调整其他内容以使其不显示。我不喜欢p/Invoke的解决方案,但它仍然比列宽调整更好。 - Robert S.
这对我也起作用了,但在最终的代码片段中,Width不应该改为类似于widthwidthValue之类的内容吗?以澄清答案并非指UI组件/控件类内部的this.Width。我差点自己编辑了字母大小写,但觉得应该由OP验证这是否是意图。 - Panzercrisis

6

目前被接受的答案是不安全的,因为它会导致堆栈不平衡。您应该使用以下代码来进行 DllImport:

[System.Runtime.InteropServices.DllImport("user32", CallingConvention=System.Runtime.InteropServices.CallingConvention.Winapi)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]

private static extern bool ShowScrollBar(IntPtr hwnd, int wBar, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)] bool bShow);

安德烈亚斯·赖夫在重新查看后在他的评论中涵盖了这一点,因此我想这里的所有内容都已经得到了良好的格式化。

为了使用它:

# Use one of these valued for hwnd
long SB_HORZ = 0;
long SB_VERT = 1;
long SB_BOTH = 3;

# Use the actual name of the ListView control in your code here
# Hides the specified ListView scroll bar
ShowScrollBar(listView1.Handle.ToInt64(), SB_BOTH, 0);

要强制它 显示 而不是 隐藏,只需将 bShow0 更改为 1,因为 0 相当于 false,而 1 相当于 true

1
有什么办法可以使用这个,但仍然允许滚动吗?我想用于垂直滚动。谢谢。 - Lee
我认为隐藏滚动条会导致禁用滚动的副作用。虽然我已经有一段时间没有编写WinForms了,但我不会说这是不可能的,而是我不知道任何方法可以隐藏滚动条同时仍允许滚动。 - codewario

6
最佳解决方案是这里给出的被接受的答案:如何在.NET ListView控件的详细模式下隐藏垂直滚动条
它完美地工作,您不需要像调整列宽度那样使用一些技巧。此外,您可以在创建控件时禁用滚动条。
缺点是您必须创建自己的列表视图类,该类派生自System.Windows.Forms.ListView以覆盖WndProc。但这是正确的方法。
要禁用水平滚动条,请记住使用WS_HSCROLL而不是WS_VSCROLL(链接答案中使用了WS_VSCROLL)。WS_HSCROLL的值为0x00100000

4
您可以尝试这样做,我曾在一个项目中使用过并且有效:

[DllImport ("user32")]
private static extern long ShowScrollBar (long hwnd , long wBar, long bShow);
long SB_HORZ = 0;
long SB_VERT = 1;
long SB_BOTH = 3;

private void HideHorizontalScrollBar ()
{
    ShowScrollBar(listView1.Handle.ToInt64(), SB_HORZ, 0);
}

希望这能有所帮助。

1
你好,能否请您解释一下这个问题,或者告诉我如何查阅所有这些直接的Windows API调用? - swordfish
1
你可以将P/Invoke方法的第一个参数从long hwnd改为IntPtr hwnd - Uwe Keim
同意,对于P/Invokes,请始终查看pinvoke。 :) http://www.pinvoke.net/default.aspx/user32/ShowScrollBar.html 给出了签名 [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, [MarshalAs(UnmanagedType.Bool)] bool bShow); 唯一的问题(我认为)是IntPtr,Uwe已经提到了。 - Andreas Reiff
2
如前所述,该答案的P/Invoke定义是明显错误的 - 不要使用它! long 是8字节,而例如对于32位进程,所有参数都需要是4字节。它之所以能够工作,仅仅是因为第二个和第三个参数恰好为零。 - Zarat

0
如果你想要一个水平显示图标或值的列表视图,只需要将对齐方式设置为左对齐。

0
我个人也在寻找类似的东西,但是无法找到如何同时移除两个滚动条并使鼠标滚轮在列表视图中起作用。我知道这与最初提出的问题不完全相关,但如果有人偶然发现这个页面并想要移除两个滚动条但仍然具有垂直滚动功能,这里是实现这一目标的代码!我在网络上搜索了很多,但找不到答案,而且这里提出的问题非常相似,所以请不要因为我在这里发布这个问题而讨厌我。还有,请不要对我的 while (1==1) 循环感到惊讶哈哈!此外,这是从许多来源(包括我自己)拼凑而成的代码,所以我不能完全归功于它,也不知道其中一些部分的原始来源。只需使用此代码创建一个新的自定义控件(将命名空间更改为您想要的),然后可以在设计.cs文件中修改所在窗体的代码,引用此控件而不是原始的ListView(只需两行代码)。确保 Scrollable 设置为 true,但同时将 ScrollOverride 设置为 true,否则它将表现为普通的 ListView。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace LancourWestbrook.Controls
{
    public partial class TPListView : ListView
    {
        [DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
        public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)]
        public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
        public static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
        public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, int dwNewLong);

        const int GWL_STYLE = -16;
        const int WS_VSCROLL = 0x00200000;
        const int WS_HSCROLL = 0x00100000;
        const int WM_MOUSEWHEEL = 0x20a;
        const int WM_NCCALCSIZE = 0x83;

        public TPListView()
        {
            InitializeComponent();
        }

        public TPListView(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        private int? LastItemIndexInView
        {
            get
            {
                if (this.Items == null || this.Items.Count <= 0)
                {
                    return null;
                }
                List<int> items = new List<int>();

                int topIndex = this.TopItem.Index;
                int currentIndex = topIndex;
                items.Add(topIndex);
                while (1 == 1)
                {
                    currentIndex++;
                    if (this.Items.Count - 1 < currentIndex)
                    {
                        break;
                    }
                    if (this.Items[currentIndex].Bounds.IntersectsWith(this.ClientRectangle))
                    {
                        items.Add(currentIndex);
                    }
                    else
                    {
                        break;
                    }
                }
                return currentIndex;
            }
        }

        public bool ScrollOverride { get; set; }

        protected override void WndProc(ref Message m)
        {            
            if (ScrollOverride == false)
            {
                base.WndProc(ref m);
                return;
            }
            switch (m.Msg)
            {
                case WM_MOUSEWHEEL:
                    if (this.Items == null || this.Items.Count <= 0)
                    {
                        break;
                    }
                    var zDelta = (short)HIWORD(m.WParam);
                    if (zDelta < 0)
                    {
                        //Scroll Downwards
                        int? lastItemInView = LastItemIndexInView;
                        if (lastItemInView.HasValue && this.Items.Count > lastItemInView.Value + 1)
                        {
                            this.Items[lastItemInView.Value + 1].EnsureVisible();
                        }
                        else if (this.Items.Count > 0)
                        {
                            this.Items[this.Items.Count - 1].EnsureVisible();
                        }
                    }
                    else if (zDelta > 0)
                    {
                        //Scroll Upwards
                        int topItemInView = this.TopItem.Index;
                        if (topItemInView > 0)
                        {
                            this.Items[topItemInView - 1].EnsureVisible();
                        }
                    }
                    break;
                case WM_NCCALCSIZE:
                    int style = (int)GetWindowLong(this.Handle, GWL_STYLE);
                    if ((style & WS_VSCROLL) == WS_VSCROLL)
                        SetWindowLong(this.Handle, GWL_STYLE, style & ~WS_VSCROLL);
                    if ((style & WS_HSCROLL) == WS_HSCROLL)
                        SetWindowLong(this.Handle, GWL_STYLE, style & ~WS_HSCROLL);                    
                    base.WndProc(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }


        public static int GetWindowLong(IntPtr hWnd, int nIndex)
        {
            if (IntPtr.Size == 4)
                return (int)GetWindowLong32(hWnd, nIndex);
            else
                return (int)(long)GetWindowLongPtr64(hWnd, nIndex);
        }

        public static int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong)
        {
            if (IntPtr.Size == 4)
                return (int)SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
            else
                return (int)(long)SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
        }

        internal static ushort HIWORD(IntPtr dwValue)
        {
            return (ushort)((((long)dwValue) >> 0x10) & 0xffff);
        }
    }
}

也许有人可以添加代码以实现鼠标滚轮点击并保持水平滚动!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接