Another 'old' bit of code that I'm still using a lot none the less. Whenever I needed drag and drop, it annoyed me that I had to use repetitive code to start it manually by tracing the mousedown etc. So what better place for repetitive code than in a reusable component. It isn't any highly fancy or complicated code, but a raincoat doesn't have to be pretty to keep you dry ;)
Anyway, when I was thinking when extending the AutoDragger today to alter the behaviour when dragging from a datagridview, that it was never posted on this blog. So here it is. (As far as I know it hasn't been outdated in the sense that .net now supports this out of the box)
Usage in Designer: drop the component on your form, select a control you wish to enable auto dragging for, locate the added 'UseAutoDrag' property on that control (under a 'Drag Drop' header) and set it to true.
(Of course the component can be used as a runtime class too.) The cursor can be set in the drag events or by setting a default drag cursor on the component.
namespace Subro.Controls
{
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
///
<summary>
/// Generic component that can start dragging for most control by handling
/// its mouse events.
/// Set the Controls property to indicate for which controls dragging should be handled
/// automatically. Catch the StartDrag event to alter the data which is to be dragged.
/// </summary>[
DefaultEvent(
"StartDrag")]
[
ProvideProperty(
"UseAutoDrag",
typeof(
Control))]
public class AutoDragger :
Component,
IExtenderProvider{
public AutoDragger()
{
}
public AutoDragger(
IContainer c)
: this()
{
c.Add(this);
}
public AutoDragger(
Control ctr)
: this(ctr, null)
{
}
public AutoDragger(
Control ctr,
EventHandler<
AutoDragEventArgs> handler)
: this()
{
Register(ctr);
if (handler !=
null)
StartDrag += handler;
}
List<Control> controls = new List<Control>();
public
int Register(
Control DragSource)
{
int i = controls.IndexOf(DragSource);
if (i != -1)
return i;
if (!DesignMode)
{
DragSource.MouseDown += new MouseEventHandler(Control_MouseDown);
DragSource.MouseMove += new MouseEventHandler(Control_MouseMove);
DragSource.MouseUp += new MouseEventHandler(Control_MouseUp);
DragSource.GiveFeedback += new GiveFeedbackEventHandler(Control_GiveFeedback);
}
controls.Add(DragSource);
i = controls.Count - 1;
ControlAdded(DragSource);
OnControlsChanged();            
return i;
}
protected virtual void ControlAdded(Control c)
{
}
public
void UnRegister(
Control DragSource)
{
DragSource.MouseDown -= new MouseEventHandler(Control_MouseDown);
DragSource.MouseMove -= new MouseEventHandler(Control_MouseMove);
DragSource.MouseUp -= new MouseEventHandler(Control_MouseUp);
DragSource.GiveFeedback -= new GiveFeedbackEventHandler(Control_GiveFeedback);
controls.Remove(DragSource);
ControlRemoved(DragSource);
OnControlsChanged();
}
protected virtual void ControlRemoved(Control c)
{
}
public
void UnRegisterAll()
{
int c = controls.Count -1;
for(
int i  = c;i>=0 ;i--)
UnRegister(controls[i]);
}const string Category = "DragDrop"
[
DefaultValue(
null)]
[
Category(Category)]
public Control[] Controls
{
get
{
return controls.ToArray();
}
set
{suspendcontrolschanged =
true;
while (controls.Count > 0)
UnRegister(controls[0]);
if (
value !=
null)
foreach (
Control c
in value)
{
Register(c);
}
suspendcontrolschanged = false;
OnControlsChanged(); } }bool suspendcontrolschanged;
protected virtual void OnControlsChanged()
{
if (!suspendcontrolschanged && ControlsChanged != null) ControlsChanged(this, EventArgs.Empty);
}public event EventHandler ControlsChanged;
public
Control this[
int Index]
{
get
{
return controls[Index];
} }///
<summary>
/// The amount of registered controls used as a dragsource
/// </summary>
public int DragSourceCount
{
get { return controls.Count; }
}public event EventHandler<AutoDragEventArgs> StartDrag;
private
DragDropEffects effects =
DragDropEffects.All;
[
DefaultValue(
DragDropEffects.All)]
public DragDropEffects Effects
{
get { return effects; }
set { effects = value; }
}protected
override void Dispose(
bool disposing)
{
UnRegisterAll();
base.Dispose(disposing);
}
int diffmin = 2;
[
DefaultValue(2)]
[
Category(Category)]
public int DifferenceMinimum
{
get {
return diffmin; }
set{
diffmin = value;
}
}
AutoDragEventArgs curdrag;
void Control_MouseDown(
object sender,
MouseEventArgs e)
{
if (e.Button ==
MouseButtons.Left)
{
curdrag = new AutoDragEventArgs(sender as Control, e.Location, this);
}
elsecurdrag = null;
}void Control_MouseUp(
object sender,
MouseEventArgs e)
{
if (curdrag !=
null)
{
AutoDragEventArgs de = curdrag;
EndCurDrag();          
OnDragEnded(de);                    
} }protected virtual void OnDragEnded(AutoDragEventArgs e)
{
}
void Control_MouseMove(
object sender,
MouseEventArgs e)
{
if (e.Button ==
MouseButtons.Left && curdrag !=
null)
{
curdrag.CheckStartDrag(e);
}
}
void Control_GiveFeedback(
object sender,
GiveFeedbackEventArgs e)
{
curdrag.SetFeedback(e);
}
private
Cursor cursor;
[
DefaultValue(
null)]
public Cursor DragCursor
{
get {
return cursor; }
set{
if (cursor == value) return;
cursor = value;
dragicon = null;
} }
bool ShouldSerializeDragCursor()
{return cursor != null && dragicon == null;
}private
Icon dragicon;
[
DefaultValue(
null)]
public Icon DragIcon
{
get {
return dragicon; }
set{
if (dragicon ==
value)
return;
if (
value ==
null)
DragCursor = null;
else
DragCursor = new Cursor(value.Handle);
dragicon =
value;
} }private
bool alwaysshowcustomcursor;
[
Description(
"Only applies when the DragCursor property is set. If this value is false, the cursor is only shown when drop is allowed")]
[
DefaultValue(
false)]
public bool AlwaysShowCustomCuror
{
get { return alwaysshowcustomcursor; }
set { alwaysshowcustomcursor = value; }
}
void EndCurDrag()
{
if (curdrag !=
null)
curdrag.Dispose();
}public
class AutoDragEventArgs :
EventArgs{
public
readonly Control Control;
public readonly Point StartPoint;
public readonly AutoDragger AutoDragger;
public AutoDragEventArgs(
Control Control,
Point StartPoint,
AutoDragger Owner)
{
this.Control = Control;
this.StartPoint = StartPoint;
this.AutoDragger = Owner;
}private
object dragobj;
public object DragObject
{
get { return dragobj; }
set { dragobj = value; }
}            private bool started;
public
bool DragStarted
{
get { return started; }                
}
internal
void CheckStartDrag(
MouseEventArgs e)
{
int diff =
Math.Abs(e.X - StartPoint.X)
+ Math.Abs(e.Y - StartPoint.Y);
if (diff >= AutoDragger.diffmin)
{
started = true;
Cursor = AutoDragger.DragCursor;
AutoDragger.OnStartDrag(this,e);
}
}public
void Dispose()
{
if (AutoDragger.curdrag ==
this)
AutoDragger.curdrag = null;
}
private Cursor cursor;public
Cursor Cursor
{
get {
return cursor; }
set{
cursor = value;                    
}
}internal
void SetFeedback(
GiveFeedbackEventArgs e)
{
if (cursor !=
null)
{
if (e.Effect !=
DragDropEffects.None || AutoDragger.alwaysshowcustomcursor)
{
e.UseDefaultCursors = false;
Cursor.Current = cursor;
}
} }internal
object GetDragObject()
{
Control c = Control;
if (c
is ListControl)
return (c as ListControl).SelectedValue;
if (c
is TextBoxBase)
return GetDragObject(c as TextBoxBase);
if (c
is Label)
return c.Text;
if (c
is TreeView)
return GetDragObject(c as TreeView);
if (c
is DataGridView)
return GetDragObject(c as DataGridView);
return null;
}object GetDragObject(
TextBoxBase tb)
{
if (!tb.ReadOnly)
{
//when in edit mode and selecting text, don't start dragging
//TODO: make optional    
return null;
}
if (tb.SelectionLength == 0)return tb.Text;
return tb.SelectedText; }object GetDragObject(
TreeView t)
{
TreeNode node = t.GetNodeAt(StartPoint);
if (node == null) return null;
t.SelectedNode = node;
return node;
}object GetDragObject(
DataGridView dg)
{
DataGridView.
HitTestInfo ht = dg.HitTest(StartPoint.X, StartPoint.Y);
if (ht.RowIndex == -1)
return null;
if (ht.ColumnIndex > -1 && !dg.Columns[ht.ColumnIndex].ReadOnly && dg[ht.ColumnIndex, ht.RowIndex].IsInEditMode)
return null; //when on a cell in edit mode, don't start drag drop
if (ht.ColumnIndex == -1 || dg.SelectionMode ==
DataGridViewSelectionMode.FullRowSelect || AutoDragger.AlwaysDragFullRow)
{
DataGridViewRow row = dg.Rows[ht.RowIndex];
if (row.DataBoundItem != null) return row.DataBoundItem;
return row;
}
return dg[ht.ColumnIndex, ht.RowIndex].Value; }}
[
Browsable(
false)]
public AutoDragEventArgs LastDragInfo
{
}protected
virtual void OnStartDrag(
AutoDragEventArgs e,
MouseEventArgs me)
{
if (StartDrag !=
null)
StartDrag(this, e);
if (e.DragObject ==
null)
e.DragObject = GetDragObject(e);
if (e.DragObject !=
null)
{
e.Control.DoDragDrop(e.DragObject, Effects);
OnDragStarted(e);
}
else{
//dragging not allowed
curdrag = null;
} }protected virtual void OnDragStarted(AutoDragEventArgs e)
{
}
protected
virtual object GetDragObject(
AutoDragEventArgs e)
{
return e.GetDragObject();
}   
private
bool fullrow;
[
DefaultValue(
false)]
[
Description(
"Only applies when dragging on a datagridview.\r\nIf this value is not set, the full row only will be dragged if the selection mode of the grid is FullRowSelect or the rowheader is dragged and the cell value otherwise.")]
public bool AlwaysDragFullRow
{
get { return fullrow; }
set { fullrow = value; }
}
#region IExtenderProvider Members
bool
IExtenderProvider.CanExtend(
object extendee)
{
return extendee is Control;
}[
DefaultValue(
false)]
[
Category(Category)]
[
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
//serialized in the control property
public bool GetUseAutoDrag(
Control c)
{
if (controls.Count == 0) return false;
return controls.Contains(c);
}
public void SetUseAutoDrag(Control c, bool value)
{if (GetUseAutoDrag(c) == value)
return;
if (!value)
UnRegister(c);
else
Register(c);
}
#endregion
}
} . . .