Archive Browser
Download ListViewInsertionDragDemo.zip version 1.0.0.0, last updated 27/07/2014 (14.12 KB)
Download- md5: 4168ad176fc85c10770000b0408f7cab
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
// Dragging items in a ListView control with visual insertion guides
// http://www.cyotek.com/blog/dragging-items-in-a-listview-control-with-visual-insertion-guides
namespace ListViewInsertionDragDemo
{
public class ListView : System.Windows.Forms.ListView
{
#region Constants
private const int WM_PAINT = 0xF;
#endregion
#region Instance Fields
private bool _allowItemDrag;
private Color _insertionLineColor;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ListView"/> class.
/// </summary>
public ListView()
{
this.DoubleBuffered = true;
this.InsertionLineColor = Color.Red;
this.InsertionIndex = -1;
}
#endregion
#region Events
/// <summary>
/// Occurs when the AllowItemDrag property value changes.
/// </summary>
[Category("Property Changed")]
public event EventHandler AllowItemDragChanged;
/// <summary>
/// Occurs when the InsertionLineColor property value changes.
/// </summary>
[Category("Property Changed")]
public event EventHandler InsertionLineColorChanged;
/// <summary>
/// Occurs when a drag-and-drop operation for an item is completed.
/// </summary>
[Category("Drag Drop")]
public event EventHandler<ListViewItemDragEventArgs> ItemDragDrop;
/// <summary>
/// Occurs when the user begins dragging an item.
/// </summary>
[Category("Drag Drop")]
public event EventHandler<CancelListViewItemDragEventArgs> ItemDragging;
#endregion
#region Overridden Methods
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Control.DragDrop" /> event.
/// </summary>
/// <param name="drgevent">A <see cref="T:System.Windows.Forms.DragEventArgs" /> that contains the event data.</param>
protected override void OnDragDrop(DragEventArgs drgevent)
{
if (this.IsRowDragInProgress)
{
try
{
ListViewItem dropItem;
dropItem = this.InsertionIndex != -1 ? this.Items[this.InsertionIndex] : null;
if (dropItem != null)
{
ListViewItem dragItem;
int dropIndex;
dragItem = (ListViewItem)drgevent.Data.GetData(typeof(ListViewItem));
dropIndex = dropItem.Index;
if (dragItem.Index < dropIndex)
{
dropIndex--;
}
if (this.InsertionMode == InsertionMode.After && dragItem.Index < this.Items.Count - 1)
{
dropIndex++;
}
if (dropIndex != dragItem.Index)
{
ListViewItemDragEventArgs args;
Point clientPoint;
clientPoint = this.PointToClient(new Point(drgevent.X, drgevent.Y));
args = new ListViewItemDragEventArgs(dragItem, dropItem, dropIndex, this.InsertionMode, clientPoint.X, clientPoint.Y);
this.OnItemDragDrop(args);
if (!args.Cancel)
{
this.Items.Remove(dragItem);
this.Items.Insert(dropIndex, dragItem);
this.SelectedItem = dragItem;
}
}
}
}
finally
{
this.InsertionIndex = -1;
this.IsRowDragInProgress = false;
this.Invalidate();
}
}
base.OnDragDrop(drgevent);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Control.DragLeave" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param>
protected override void OnDragLeave(EventArgs e)
{
this.InsertionIndex = -1;
this.Invalidate();
base.OnDragLeave(e);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Control.DragOver" /> event.
/// </summary>
/// <param name="drgevent">A <see cref="T:System.Windows.Forms.DragEventArgs" /> that contains the event data.</param>
protected override void OnDragOver(DragEventArgs drgevent)
{
if (this.IsRowDragInProgress)
{
int insertionIndex;
InsertionMode insertionMode;
ListViewItem dropItem;
Point clientPoint;
clientPoint = this.PointToClient(new Point(drgevent.X, drgevent.Y));
dropItem = this.GetItemAt(0, Math.Min(clientPoint.Y, this.Items[this.Items.Count - 1].GetBounds(ItemBoundsPortion.Entire).Bottom - 1));
if (dropItem != null)
{
Rectangle bounds;
bounds = dropItem.GetBounds(ItemBoundsPortion.Entire);
insertionIndex = dropItem.Index;
insertionMode = clientPoint.Y < bounds.Top + (bounds.Height / 2) ? InsertionMode.Before : InsertionMode.After;
drgevent.Effect = DragDropEffects.Move;
}
else
{
insertionIndex = -1;
insertionMode = this.InsertionMode;
drgevent.Effect = DragDropEffects.None;
}
if (insertionIndex != this.InsertionIndex || insertionMode != this.InsertionMode)
{
this.InsertionMode = insertionMode;
this.InsertionIndex = insertionIndex;
this.Invalidate();
}
}
base.OnDragOver(drgevent);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.ListView.ItemDrag" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.Windows.Forms.ItemDragEventArgs" /> that contains the event data.</param>
protected override void OnItemDrag(ItemDragEventArgs e)
{
if (this.AllowItemDrag && this.Items.Count > 1)
{
CancelListViewItemDragEventArgs args;
args = new CancelListViewItemDragEventArgs((ListViewItem)e.Item);
this.OnItemDragging(args);
if (!args.Cancel)
{
this.IsRowDragInProgress = true;
this.DoDragDrop(e.Item, DragDropEffects.Move);
}
}
base.OnItemDrag(e);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
/// </summary>
/// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data. </param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
/// <summary>
/// Overrides <see cref="M:System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message@)" />.
/// </summary>
/// <param name="m">The Windows <see cref="T:System.Windows.Forms.Message" /> to process.</param>
[DebuggerStepThrough]
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_PAINT:
this.OnWmPaint(ref m);
break;
}
}
#endregion
#region Public Properties
[Category("Behavior")]
[DefaultValue(false)]
public virtual bool AllowItemDrag
{
get { return _allowItemDrag; }
set
{
if (this.AllowItemDrag != value)
{
_allowItemDrag = value;
this.OnAllowItemDragChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the color of the insertion line drawn when dragging items within the control.
/// </summary>
/// <value>The color of the insertion line.</value>
[Category("Appearance")]
[DefaultValue(typeof(Color), "Red")]
public virtual Color InsertionLineColor
{
get { return _insertionLineColor; }
set
{
if (this.InsertionLineColor != value)
{
_insertionLineColor = value;
this.OnInsertionLineColorChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Gets or sets the selected <see cref="ListViewItem"/>.
/// </summary>
/// <value>The selected <see cref="ListViewItem"/>.</value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ListViewItem SelectedItem
{
get { return this.SelectedItems.Count != 0 ? this.SelectedItems[0] : null; }
set
{
this.SelectedItems.Clear();
if (value != null)
{
value.Selected = true;
}
this.FocusedItem = value;
}
}
#endregion
#region Protected Properties
protected int InsertionIndex { get; set; }
protected InsertionMode InsertionMode { get; set; }
protected bool IsRowDragInProgress { get; set; }
#endregion
#region Protected Members
/// <summary>
/// Raises the <see cref="AllowItemDragChanged" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnAllowItemDragChanged(EventArgs e)
{
EventHandler handler;
handler = this.AllowItemDragChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="InsertionLineColorChanged" /> event.
/// </summary>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
protected virtual void OnInsertionLineColorChanged(EventArgs e)
{
EventHandler handler;
handler = this.InsertionLineColorChanged;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="ItemDragDrop" /> event.
/// </summary>
/// <param name="e">The <see cref="ListViewItemDragEventArgs" /> instance containing the event data.</param>
protected virtual void OnItemDragDrop(ListViewItemDragEventArgs e)
{
EventHandler<ListViewItemDragEventArgs> handler;
handler = this.ItemDragDrop;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Raises the <see cref="ItemDragging" /> event.
/// </summary>
/// <param name="e">The <see cref="CancelListViewItemDragEventArgs" /> instance containing the event data.</param>
protected virtual void OnItemDragging(CancelListViewItemDragEventArgs e)
{
EventHandler<CancelListViewItemDragEventArgs> handler;
handler = this.ItemDragging;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnWmPaint(ref Message m)
{
this.DrawInsertionLine();
}
#endregion
#region Private Members
private void DrawInsertionLine()
{
if (this.InsertionIndex != -1)
{
int index;
index = this.InsertionIndex;
if (index >= 0 && index < this.Items.Count)
{
Rectangle bounds;
int x;
int y;
int width;
bounds = this.Items[index].GetBounds(ItemBoundsPortion.Entire);
x = 0; // aways fit the line to the client area, regardless of how the user is scrolling
y = this.InsertionMode == InsertionMode.Before ? bounds.Top : bounds.Bottom;
width = Math.Min(bounds.Width - bounds.Left, this.ClientSize.Width); // again, make sure the full width fits in the client area
this.DrawInsertionLine(x, y, width);
}
}
}
private void DrawInsertionLine(int x1, int y, int width)
{
using (Graphics g = this.CreateGraphics())
{
Point[] leftArrowHead;
Point[] rightArrowHead;
int arrowHeadSize;
int x2;
x2 = x1 + width;
arrowHeadSize = 7;
leftArrowHead = new[]
{
new Point(x1, y - (arrowHeadSize / 2)), new Point(x1 + arrowHeadSize, y), new Point(x1, y + (arrowHeadSize / 2))
};
rightArrowHead = new[]
{
new Point(x2, y - (arrowHeadSize / 2)), new Point(x2 - arrowHeadSize, y), new Point(x2, y + (arrowHeadSize / 2))
};
using (Pen pen = new Pen(this.InsertionLineColor))
{
g.DrawLine(pen, x1, y, x2 - 1, y);
}
using (Brush brush = new SolidBrush(this.InsertionLineColor))
{
g.FillPolygon(brush, leftArrowHead);
g.FillPolygon(brush, rightArrowHead);
}
}
}
#endregion
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate