You can opt this solution to reorder the dropped controls into a FlowLayoutPanel control. The part that utilizes the Control.ControlCollection.GetChildIndex and Control.ControlCollection.SetChildIndex methods.
Let's say you have a custom Control or UserControl named DragDropControl:
public class DragDropControl : Control
{
public DragDropControl()
{
AllowDrop = true;
BackColor = Color.LightSteelBlue;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
TextRenderer.DrawText(e.Graphics, Text, Font,
ClientRectangle, Color.Black,
TextFormatFlags.HorizontalCenter |
TextFormatFlags.VerticalCenter);
}
}
Note: From what I see in the images, just use a simple Label control instead.
Let's create a custom FlowLayoutPanel and encapsulate all the required functionalities to not repeat that in your implementation for each FLP.
public class DragDropFlowLayoutPanel : FlowLayoutPanel
{
public DragDropFlowLayoutPanel()
{
AllowDrop = true;
}
[DefaultValue(true)]
public override bool AllowDrop
{
get => base.AllowDrop;
set => base.AllowDrop = value;
}
The custom FLP implements the mouse, drag and drop events of its children as well.
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control is DragDropControl)
{
e.Control.DragOver += OnControlDragOver;
e.Control.DragDrop += OnControlDragDrop;
e.Control.MouseDown += OnControlMouseDown;
}
}
protected override void OnControlRemoved(ControlEventArgs e)
{
base.OnControlRemoved(e);
e.Control.DragOver -= OnControlDragOver;
e.Control.DragDrop -= OnControlDragDrop;
e.Control.MouseDown -= OnControlMouseDown;
}
Handle the child controls MouseDown event to do the drag:
private void OnControlMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var control = sender as DragDropControl;
DoDragDrop(control, DragDropEffects.Move);
}
}
Handle the DragEnter and DragOver methods and events of the FLP and its children to set the drop effect.
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragOver(DragEventArgs e)
{
base.OnDragOver(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
private void OnControlDragOver(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
if (GetChildAtPoint(p) == ddc)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
}
}
Finally, call from the DragDrop method override and event the DropControl method and pass the DragEventArgs param.
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
DropControl(e);
}
private void OnControlDragDrop(object sender, DragEventArgs e)
{
DropControl(e);
}
The dropped control takes the index of the control under the mouse position if any otherwise it will be inserted at the end of the Controls collection.
private void DropControl(DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
var child = GetChildAtPoint(p);
var index = child == null
? Controls.Count
: Controls.GetChildIndex(child);
ddc.Parent = this;
Controls.SetChildIndex(ddc, index);
}
}
}
Put it all together.
public class DragDropFlowLayoutPanel : FlowLayoutPanel
{
public DragDropFlowLayoutPanel()
{
AllowDrop = true;
}
[DefaultValue(true)]
public override bool AllowDrop
{
get => base.AllowDrop;
set => base.AllowDrop = value;
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control is DragDropControl)
{
e.Control.DragOver += OnControlDragOver;
e.Control.DragDrop += OnControlDragDrop;
e.Control.MouseDown += OnControlMouseDown;
}
}
protected override void OnControlRemoved(ControlEventArgs e)
{
base.OnControlRemoved(e);
e.Control.DragOver -= OnControlDragOver;
e.Control.DragDrop -= OnControlDragDrop;
e.Control.MouseDown -= OnControlMouseDown;
}
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragOver(DragEventArgs e)
{
base.OnDragOver(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
DropControl(e);
}
private void OnControlDragOver(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
if (GetChildAtPoint(p) == ddc)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
}
}
private void OnControlDragDrop(object sender, DragEventArgs e)
{
DropControl(e);
}
private void OnControlMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var control = sender as DragDropControl;
DoDragDrop(control, DragDropEffects.Move);
}
}
private void DropControl(DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
var child = GetChildAtPoint(p);
var index = child == null
? Controls.Count
: Controls.GetChildIndex(child);
ddc.Parent = this;
Controls.SetChildIndex(ddc, index);
}
}
}
