views:

2987

answers:

5

Hi, How do I implement Auto-Scrolling (e.g. the ListView scrolls when you near the top or bottom) in a Winforms ListView? I've hunted around on google with little luck. I can't believe this doesn't work out of the box! Thanks in advance Dave

+3  A: 

This may be of use though it's vb.net link

Sean Storey
A: 

Listen for the mouse entry. When the mouse enters, test if the mouse is down or not. Then listen for mouse motion. If the position of the motion is near the top or the bottom, scroll the listbox up or down (there are built-in functions to scroll).

I would also hook up some sort of asynchronous check to keep the thing scrolling while the mouse in in the desired region. I'll post code when I get around to booting into Windows (or if someone else wants to write a sample implementation, I'd be thrilled).

I don't know if you'll be able to get any sort of smooth scrolling going (the performance hit of scrolling a tiny bit several times per second may be too much), but this will certainly provide d'n'd scrolling, albeit choppily.

Davis Gallinghouse
+5  A: 

Thanks for the link, I C#ised it

class ListViewBase:ListView
{
    private Timer tmrLVScroll;
    private System.ComponentModel.IContainer components;
    private int mintScrollDirection;
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
    const int WM_VSCROLL = 277; // Vertical scroll
    const int SB_LINEUP = 0; // Scrolls one line up
    const int SB_LINEDOWN = 1; // Scrolls one line down

    public ListViewBase()
    {
        InitializeComponent();
    }
    protected void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.tmrLVScroll = new System.Windows.Forms.Timer(this.components);
        this.SuspendLayout();
        // 
        // tmrLVScroll
        // 
        this.tmrLVScroll.Tick += new System.EventHandler(this.tmrLVScroll_Tick);
        // 
        // ListViewBase
        // 
        this.DragOver += new System.Windows.Forms.DragEventHandler(this.ListViewBase_DragOver);
        this.ResumeLayout(false);

    }

    protected void ListViewBase_DragOver(object sender, DragEventArgs e)
    {
        Point position = PointToClient(new Point(e.X, e.Y));

        if (position.Y <= (Font.Height / 2))
        {
            // getting close to top, ensure previous item is visible
            mintScrollDirection = SB_LINEUP;
            tmrLVScroll.Enabled = true;
        }else if (position.Y >= ClientSize.Height - Font.Height / 2)
        { 
            // getting close to bottom, ensure next item is visible
            mintScrollDirection = SB_LINEDOWN;
            tmrLVScroll.Enabled = true;
        }else{
            tmrLVScroll.Enabled = false;
        }
    }

    private void tmrLVScroll_Tick(object sender, EventArgs e)
    {
        SendMessage(Handle, WM_VSCROLL, (IntPtr)mintScrollDirection, IntPtr.Zero);
    }
}
David Hayes
+2  A: 

Have a look at ObjectListView. It does this stuff. You can read the code and use that if you don't want to use the ObjectListView itself.

Grammarian
A: 

Just a note for future googlers: to get this working on more complex controls (such as DataGridView), see this thread.

BlueRaja - Danny Pflughoeft