Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Implementing Auto-Scroll in a ListView while Drag & Dropping

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

like image 620
David Hayes Avatar asked Mar 19 '09 00:03

David Hayes


2 Answers

Thanks for the link (http://www.knowdotnet.com/articles/listviewdragdropscroll.html), 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);
    }
}
like image 116
David Hayes Avatar answered Nov 08 '22 04:11

David Hayes


Scrolling can be accomplished with the ListViewItem.EnsureVisible method. You need to determine if the item you are currently dragging over is at the visible boundary of the list view and is not the first/last.

private static void RevealMoreItems(object sender, DragEventArgs e)
{
    var listView = (ListView)sender;

    var point = listView.PointToClient(new Point(e.X, e.Y));
    var item = listView.GetItemAt(point.X, point.Y);
    if (item == null)
        return;

    var index = item.Index;
    var maxIndex = listView.Items.Count;
    var scrollZoneHeight = listView.Font.Height;

    if (index > 0 && point.Y < scrollZoneHeight)
    {
        listView.Items[index - 1].EnsureVisible();
    }
    else if (index < maxIndex && point.Y > listView.Height - scrollZoneHeight)
    {
        listView.Items[index + 1].EnsureVisible();
    }
}

Then wire this method to the DragOver event.

targetListView.DragOver += RevealMoreItems;

targetListView.DragOver += (sender, e) =>
{
    e.Effect = DragDropEffects.Move;
};
like image 20
George Polevoy Avatar answered Nov 08 '22 05:11

George Polevoy