有没有办法在C#WinForms中自动滚动列表框

时间:2015-02-02 19:20:19

标签: c# winforms listboxitems

我写一个程序会在大显示器的几个列表框中显示一个数字列表,我的问题是有没有办法自动滚动列表框以显示框中的所有数据?

2 个答案:

答案 0 :(得分:4)

通常,我会这样做:

listBox.SelectedIndex = listBox.Items.Count - 1;
listBox.SelectedIndex = -1;

但您也可以尝试

int nItems = (int)(listBox.Height / listBox.ItemHeight);
listBox.TopIndex = listBox.Items.Count - nItems;

希望这会有所帮助:)

答案 1 :(得分:1)

要在不选择项目的情况下直接控制滚动,您需要使用SetScrollPos中的Win32 User32.dll方法。这是一个扩展类,为您提供基本支持:

public class ScrollableListView : ListView
{
    private const int WM_VSCROLL = 0x115;

    private enum ScrollBar : int { Horizontal = 0x0, Vertical = 0x1 }

    public void SetScroll(int x, int y)
    {
        this.SetScroll(ScrollBar.Horizontal, x);
        this.SetScroll(ScrollBar.Vertical, y);
    }

    public void SetScrollX(int position)
    {
        this.SetScroll(ScrollBar.Horizontal, position);
    }

    public void SetScrollY(int position)
    {
        this.SetScroll(ScrollBar.Vertical, position);
    }

    [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
    private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    [DllImport("user32.dll")]
    private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

    private void SetScroll(ScrollBar bar, int position)
    {
        if (!this.IsDisposed)
        {
            ScrollableListView.SetScrollPos((IntPtr)this.Handle, (int)bar, position, true);
            ScrollableListView.PostMessage((IntPtr)this.Handle, ScrollableListView.WM_VSCROLL, 4 + 0x10000 * position, 0);
        }
    }
}

然后,您可以快速轻松地设置X或Y滚动。这也适用于其他控件。


如果您想让控件自动向下和向上滚动,您需要设置一个定期计时器,间隔大约为20毫秒。跟踪滚动位置和方向,并相应地增加或减少它,使用这些方法将位置发送到控件。


<强>更新

我上面发布的SetScrollPos方法存在一些问题,主要是滚动条移动,但内容不是。它可能只是一个小小的疏忽,但与此同时,这是一个有点&#34;在框外&#34; MarqueeListView解决方案..

首先,枚举表示要使用的滚动条。我为这些(SB_HORIZSB_VERT)使用了显示名称而不是Win32名称,只是为了让事情更加清晰。

public enum ScrollBarDirection : int { Horizontal = 0x0, Vertical = 0x1 }

滚动命令的另一个枚举代码本身 - 除了向上(SB_LINEUP),向下(SB_LINEDOWN)和EndScroll(SB_ENDSCROLL)之外,我已经删除了所有内容。滚动消息后需要EndScroll以通知控件更新。

public enum ScrollCommand : int { Up = 0x0, Down = 0x1, EndScroll = 0x8 }

然后最后是班级本身。它基本上是每20ms向下滚动一次(默认情况下 - 注意这可以通过MarqueeSpeed属性更改)。然后获取滚动位置,并将其与上次进行比较。滚动条停止移动后,它会反转方向。这是为了解决我使用GetScrollInfo方法时遇到的问题。

public class MarqueeListView : ListView
{
    protected const int WM_VSCROLL = 0x115;

    private ScrollCommand scrollCommand;
    private int scrollPositionOld;
    private Timer timer;

    public MarqueeListView()
        : base()
    {
        this.MarqueeSpeed = 20;

        this.scrollPositionOld = int.MinValue;
        this.scrollCommand = ScrollCommand.Down;

        this.timer = new Timer() { Interval = this.MarqueeSpeed };
        this.timer.Tick += (sender, e) =>
        {
            int scrollPosition = MarqueeListView.GetScrollPos((IntPtr)this.Handle, (int)ScrollBarDirection.Vertical);
            if (scrollPosition == this.scrollPositionOld)
            {
                if (this.scrollCommand == ScrollCommand.Down)
                {
                    this.scrollCommand = ScrollCommand.Up;
                }
                else
                {
                    this.scrollCommand = ScrollCommand.Down;
                }
            }
            this.scrollPositionOld = scrollPosition;

            MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)this.scrollCommand, IntPtr.Zero);
            MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)ScrollCommand.EndScroll, IntPtr.Zero);
        };
        this.timer.Start();
    }

    public int MarqueeSpeed
    {
        get
        {
            return this.timer.Interval;
        }
        set
        {
            this.timer.Interval = value;
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetScrollPos(IntPtr hWnd, int nBar);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    protected static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
}

最后,这是一个快速的主要方法来测试它:

    private static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Form form = new Form() { StartPosition = FormStartPosition.CenterScreen, Width = 1280, Height = 720 };
        MarqueeListView list = new MarqueeListView() { View = View.Tile, Dock = DockStyle.Fill };
        for (int i = 0; i < 1000; i++) { list.Items.Add(Guid.NewGuid().ToString()); }
        form.Controls.Add(list);

        Application.Run(form);
    }

请记住,这不一定是&#34;正确的&#34;或者最好的做事方式,但我认为不同的方法可能会给你一些想法!

我希望使用SetScrollPos,这会产生更好,更顺畅的效果。然后你可以很容易地加入加速和减速 - 可能选择在鼠标停止时减速停止,然后在鼠标移开时加速等等。虽然目前不玩球 - 但我有一个工作滚动更新在某个旧项目中的方法,所以如果我再次使用它,我会更新它。

希望有所帮助!