Click here to Skip to main content
15,893,381 members
Articles / Programming Languages / C#
Article

Drag and Drop ListView row reordering

Rate me:
Please Sign up or sign in to vote.
4.67/5 (40 votes)
11 Nov 20032 min read 329.5K   15.8K   95   36
This article presents a simple ListView control that provides row reordering using Drag and Drop.

Introduction

An application I worked on required a mechanism whereby the user could rearrange the index of a row within a ListView control at runtime. For this, I wanted to use Drag and Drop, however after trailing through the Internet for some examples, I was unable to find something specific to C#, therefore I decided to implement my own.

Using the code

The ListView control presented here adds the property AllowRowReorder to the existing .NET ListView, which enables or disables the control's ability to reorder it rows.

In order to provide Drag and Drop support to the control, the methods OnItemDrag, OnDragEnter and OnDragDrop of the base control must be overridden. OnItemDrag is the method called once the control detects that a Drag and Drop operation has begun. It is here that any pre 'Drag and Drop' logic must be performed; this entails ensuring that row reordering has been enabled. Finally to inform the ListView that the Drag and Drop operation is valid, the DoDragDrop method is called, the first parameter being the Drag data, which identifies the object to be dragged and needs to be a String, Bitmap or a MetaFile. For the ListView provided, this is a hard-coded string, which will be used in the OnDragEnter method for Drop validation, since the items to be dragged will implicitly be the currently selected ListView items.

C#
protected override void OnItemDrag(ItemDragEventArgs e)
{
  base.OnItemDrag(e);
  if(!this.AllowRowReorder)
  {
    return;
  }
  base.DoDragDrop(REORDER, DragDropEffects.Move);
}

The OnDragEnter validates whether or not the item being dragged, as identified by the DragEventArgs.Data object, can be dropped into the control. Note that when Drag and Drop is enabled within the control, it must provide logic to handle drag events from all drag enabled sources. The ListView provided simply ensures that the data passed matches the hard-coded value supplied by the OnItemDrag method.

C#
protected override void OnDragEnter(DragEventArgs e)
{
  base.OnDragEnter(e);
  if(!this.AllowRowReorder)
  {
    e.Effect = DragDropEffects.None;
    return;
  }
  if(!e.Data.GetDataPresent(DataFormats.Text))
  {
    e.Effect = DragDropEffects.None;
    return;
  }
  String text = (String)e.Data.GetData(REORDER.GetType());
  if(text.CompareTo(REORDER)==0)
  {
    e.Effect = DragDropEffects.Move;
  }
  else
  {
    e.Effect = DragDropEffects.None; 
  }
}

Subsequently, OnDragOver ensures the continuing validity of the Drop operation as you move the mouse over the items in the control.

C#
protected override void OnDragOver(DragEventArgs e)
{
  if(!this.AllowRowReorder)
  {
    e.Effect = DragDropEffects.None;
    return;
  }
  if(!e.Data.GetDataPresent(DataFormats.Text))
  {
    e.Effect = DragDropEffects.None;
    return;
  }
  Point cp = base.PointToClient(new Point(e.X, e.Y));
  ListViewItem hoverItem = base.GetItemAt(cp.X, cp.Y);
  if(hoverItem==null)
  {
    e.Effect = DragDropEffects.None;
    return;
  }
  foreach(ListViewItem moveItem in base.SelectedItems)
  {
    if(moveItem.Index==hoverItem.Index)
    {
        e.Effect = DragDropEffects.None;
        hoverItem.EnsureVisible();
        return;
    }
  }
  base.OnDragOver(e);
  String text = (String)e.Data.GetData(REORDER.GetType());
  if(text.CompareTo(REORDER)==0)
  {
    e.Effect = DragDropEffects.Move;
    hoverItem.EnsureVisible();
  }
  else
  {
    e.Effect = DragDropEffects.None;        
  }
}

Finally OnDragDrop performs the actual Drop operation, this includes identifying the ListViewItems to be moved and the row index they will be moved to. Notice that I’m assuming that the ListViewItems to be moved are the control's currently selected items.

C#
protected override void OnDragDrop(DragEventArgs e)
{
  base.OnDragDrop(e);
  if(!this.AllowRowReorder)
  {
    return;
  }
  if(base.SelectedItems.Count==0)
  {
    return;
  }
  Point cp = base.PointToClient(new Point(e.X, e.Y));
  ListViewItem dragToItem = base.GetItemAt(cp.X, cp.Y);
  if(dragToItem==null)
  {
    return;
  }
  int dropIndex = dragToItem.Index;
  if(dropIndex>base.SelectedItems[0].Index)
  {
    dropIndex++;
  }
  ArrayList insertItems = 
    new ArrayList(base.SelectedItems.Count);
  foreach(ListViewItem item in base.SelectedItems)
  {
    insertItems.Add(item.Clone());
  }
  for(int i=insertItems.Count-1;i>=0;i--)
  {
    ListViewItem insertItem =
     (ListViewItem)insertItems[i];
    base.Items.Insert(dropIndex, insertItem);
  }
  foreach(ListViewItem removeItem in base.SelectedItems)
  {
    base.Items.Remove(removeItem);
  }
}

Downloads

Source and demo projects have been created using #Develop.

Update

  • 6th October 2003 - Fix for reordering problem when dragging multiple items.
  • 10 November 2003 – Updated for automatic scrolling during a Drag operation (suggestion from JayBarry and Brian Pierson)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Doesn´t works in View.LargeIcon mode [modified] Pin
Milky Way18-Jun-06 21:43
Milky Way18-Jun-06 21:43 
AnswerRe: Doesn´t works in View.LargeIcon mode Pin
ntiagobr24-Oct-06 9:01
ntiagobr24-Oct-06 9:01 
QuestionScrolling within the listbox? Pin
JayBarry29-Oct-03 7:17
JayBarry29-Oct-03 7:17 
AnswerRe: Scrolling within the listbox? Pin
JayBarry29-Oct-03 8:45
JayBarry29-Oct-03 8:45 
GeneralRe: Scrolling within the listbox? Pin
Brian Pierson10-Nov-03 4:54
Brian Pierson10-Nov-03 4:54 
GeneralRe: Scrolling within the listbox? Pin
David Boland10-Nov-03 5:44
David Boland10-Nov-03 5:44 
GeneralRe: Scrolling within the listbox? Pin
Maximilian Reuter28-Jun-16 0:20
Maximilian Reuter28-Jun-16 0:20 
QuestionHow to sort rows as well as columns? Pin
Bakutotsu15-Oct-03 6:22
Bakutotsu15-Oct-03 6:22 
Howdy, I've emplemented your code and the code from

http://www.c-sharpcorner.com/Code/2002/May/MultiColumnListViewSorting.asp

to try and sort a listview table by row AND column. What I'm looking to do is allow the user to sort data in a listview control by clicking onto the column header along with allowing the user to move data around a whole row at a time. The implementation is as a new form control that I drag drop onto my form and then set properties via the .NET ide. The thing is this, I can do only one or the other. Allow me to explain. I have three tables, one is set to sort via row another is set to sort via column and one is set to sort via row and column. The row sortable table works just fine. The column sortable table works just fine. However, the row and column sortable table only allows me to sort via column.

I can send the control's source code to you if you wish.

Update: BTW..further testing has shown that I can sort via row in the third table type if I don't sort via column. Once I sort via column, I cannot sort via row and can only sort via column. Further testing showed that if I comment out the line of code where the ListViewItemSorter is set in the column sortable code, I can sort via row even after sorting via column. I believe this shows some kind of incompatability between the row and column sorting code centered around the ListViewItemSorter. Hope this extra info helps.

Thanks in advance!

Update: Nevermind.. I figure it out. It's a friggin hack but it works. I save the ListViewSorter as a IComparer type before I do the column sort, then after the column sort I set it back to it's original value. Yea it's a hack but it wurks fo me.


AnswerRe: How to sort rows as well as columns? Pin
David Boland15-Oct-03 22:57
David Boland15-Oct-03 22:57 
GeneralDragging more than one item Pin
Brian Heitt24-Aug-03 7:16
Brian Heitt24-Aug-03 7:16 
GeneralRe: Dragging more than one item Pin
JayBarry3-Oct-03 8:47
JayBarry3-Oct-03 8:47 
GeneralRe: Dragging more than one item Pin
David Boland5-Oct-03 22:38
David Boland5-Oct-03 22:38 
QuestionReorder ?? Pin
azusakt4-Aug-03 16:25
azusakt4-Aug-03 16:25 
AnswerRe: Reorder ?? Pin
dboland4-Aug-03 23:09
dboland4-Aug-03 23:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.