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

后端 未结 4 603
南笙
南笙 2021-01-05 22:07

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\'

相关标签:
4条回答
  • 2021-01-05 22:11

    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;
    };
    
    0 讨论(0)
  • 2021-01-05 22:29

    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);
        }
    }
    
    0 讨论(0)
  • 2021-01-05 22:32

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

    0 讨论(0)
  • 2021-01-05 22:34

    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.

    0 讨论(0)
提交回复
热议问题