Click here to Skip to main content
15,891,423 members
Articles / Programming Languages / C#

Manual Reordering of Items inside a ListView

Rate me:
Please Sign up or sign in to vote.
4.79/5 (19 votes)
9 Jan 2008Ms-PL6 min read 109.5K   5.2K   68  
This article shows how to implement drag&drop inside a ListView and how to enable custom painting in a ListView.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ListViewCustomReorder
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // Important:
            // Right now it's not possible to drag more than one LVItem, so make sure the LV is in single selection mode
            listView1.MultiSelect = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Fill the LV with test values
            for (int i = 0; i < 20; i++)
            {
                ListViewItem it = new ListViewItem("Item " + i);
                it.SubItems.Add("Item " + i + "-1");
                it.SubItems.Add("Item " + i + "-2");
                it.SubItems.Add("Item " + i + "-3");
                listView1.Items.Add(it);
            }
        }

        // The LVItem being dragged
        private ListViewItem _itemDnD = null;
        
        private void listView1_MouseDown(object sender, MouseEventArgs e)
        {
            _itemDnD = listView1.GetItemAt(e.X, e.Y);
            // if the LV is still empty, no item will be found anyway, so we don't have to consider this case
        }

        private void listView1_MouseMove(object sender, MouseEventArgs e)
        {
            if (_itemDnD == null)
                return;

            // Show the user that a drag operation is happening
            Cursor = Cursors.Hand;

            // calculate the bottom of the last item in the LV so that you don't have to stop your drag at the last item
            int lastItemBottom = Math.Min(e.Y, listView1.Items[listView1.Items.Count-1].GetBounds(ItemBoundsPortion.Entire).Bottom-1);

            // use 0 instead of e.X so that you don't have to keep inside the columns while dragging
            ListViewItem itemOver = listView1.GetItemAt(0, lastItemBottom);

            if (itemOver == null)
                return;

            Rectangle rc = itemOver.GetBounds(ItemBoundsPortion.Entire);
            if (e.Y < rc.Top + (rc.Height / 2))
            {
                listView1.LineBefore = itemOver.Index;
                listView1.LineAfter = -1;
            }
            else
            {
                listView1.LineBefore = -1;
                listView1.LineAfter = itemOver.Index;
            }

            // invalidate the LV so that the insertion line is shown
            listView1.Invalidate();
        }

        private void listView1_MouseUp(object sender, MouseEventArgs e)
        {
            if (_itemDnD == null)
                return;

            try
            {
                // calculate the bottom of the last item in the LV so that you don't have to stop your drag at the last item
                int lastItemBottom = Math.Min(e.Y, listView1.Items[listView1.Items.Count - 1].GetBounds(ItemBoundsPortion.Entire).Bottom - 1);

                // use 0 instead of e.X so that you don't have to keep inside the columns while dragging
                ListViewItem itemOver = listView1.GetItemAt(0, lastItemBottom);

                if (itemOver == null)
                    return;

                Rectangle rc = itemOver.GetBounds(ItemBoundsPortion.Entire);

                // find out if we insert before or after the item the mouse is over
                bool insertBefore;
                if (e.Y < rc.Top + (rc.Height / 2))
                {
                    insertBefore = true;
                }
                else
                {
                    insertBefore = false;
                }

                if (_itemDnD != itemOver) // if we dropped the item on itself, nothing is to be done
                {
                    if (insertBefore)
                    {
                        listView1.Items.Remove(_itemDnD);
                        listView1.Items.Insert(itemOver.Index, _itemDnD);
                    }
                    else
                    {
                        listView1.Items.Remove(_itemDnD);
                        listView1.Items.Insert(itemOver.Index + 1, _itemDnD);
                    }
                }

                // clear the insertion line
                listView1.LineAfter =
                listView1.LineBefore = -1;

                listView1.Invalidate();

            }
            finally
            {
                // finish drag&drop operation
                _itemDnD = null;
                Cursor = Cursors.Default;
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer (Senior) 4voice AG
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions