Skip to content

Instantly share code, notes, and snippets.

@Crisfole
Created May 21, 2012 17:06
Show Gist options
  • Save Crisfole/2763319 to your computer and use it in GitHub Desktop.
Save Crisfole/2763319 to your computer and use it in GitHub Desktop.
A useful drag and drop extension method
public static void SetupDragging(this ListView list)
{
bool insertAfter = false;
ListViewItem dragged = null;
ListViewItem targetItem = null;
list.DrawItem += (o, e) =>
{
e.DrawDefault = true;
if (e.Item != targetItem) return;
e.DrawDefault = false;
e.DrawBackground();
e.DrawFocusRectangle();
e.DrawText();
using (var pen = new Pen(Color.DarkGreen, 1.0f))
{
Point start = new Point(e.Bounds.Left + e.Bounds.Width / 4, insertAfter ? e.Bounds.Bottom - 1 : e.Bounds.Top);
Point end = new Point(e.Bounds.Width - e.Bounds.Width / 4, insertAfter ? e.Bounds.Bottom - 1 : e.Bounds.Top);
e.Graphics.DrawLine(pen, start, end);
}
};
list.ItemDrag += (o, e) =>
{
list.OwnerDraw = true;
dragged = (ListViewItem)e.Item;
list.DoDragDrop(e.Item, DragDropEffects.Move);
};
bool hovering = false;
list.DragOver += (o, e) =>
{
Point targetPoint = list.PointToClient(new Point(e.X, e.Y));
targetItem = list.GetItemAt(targetPoint.X, targetPoint.Y);
Rectangle itemBounds = targetItem.Bounds;
bool atTopItem = list.TopItem == targetItem && list.Items[0] != targetItem;
bool atBottomItem = targetPoint.Y > list.Height - itemBounds.Height && targetItem.Index < list.Items.Count - 1;
if (!hovering && atTopItem)
{
hovering = true;
Timer t = new Timer { Interval = 400 };
ListViewItem currentTarget = targetItem;
t.Tick += (o1, e1) =>
{
t.Stop();
if (currentTarget == targetItem)
{
list.Items[currentTarget.Index - 1].EnsureVisible();
}
hovering = false;
};
t.Start();
}
else if (!hovering && atBottomItem)
{
hovering = true;
Timer t = new Timer { Interval = 400 };
ListViewItem currentTarget = targetItem;
t.Tick += (o1, e1) =>
{
t.Stop();
if (currentTarget == targetItem)
{
list.Items[currentTarget.Index + 1].EnsureVisible();
}
hovering = false;
};
t.Start();
}
else if (hovering && !atTopItem && !atBottomItem)
{
hovering = false;
}
if (targetItem == dragged) targetItem = null;
if (targetItem == null)
{
e.Effect = DragDropEffects.None;
list.Invalidate();
}
else
{
e.Effect = DragDropEffects.Move;
insertAfter = targetPoint.Y > itemBounds.Top + (itemBounds.Height / 2);
itemBounds.Inflate(10, 10);
itemBounds.Offset(-5, -5);
list.Invalidate(itemBounds);
}
};
list.DragEnter += (o, e) =>
{
list.OwnerDraw = dragged != null;
list.Invalidate();
};
list.DragLeave += (o, e) =>
{
list.OwnerDraw = false;
targetItem = null;
list.Invalidate();
};
list.DragDrop += (o, e) =>
{
if (targetItem != null)
{
int targetIndex = targetItem.Index;
if (insertAfter) ++targetIndex;
var tmp = new ListViewItem();
list.Items.Insert(targetIndex, tmp);
list.Items.Remove(dragged);
list.Items.Insert(tmp.Index, dragged);
list.Items.Remove(tmp);
}
list.OwnerDraw = false;
list.Invalidate();
};
}
@Crisfole
Copy link
Author

Very handy so you don't reuse the same code over and over. Allows you to re-order the items in a DetailMode non-virtual list view by simply calling SetupDragging on the list view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment