I am creating a windows form with several panels (10) in a flow layout panel, and I want these panels to be able to drag and drop to preferably another flow layout panel on top of it. I don't want the panels to overlap. I want to be able to track their position in the flow layout panel and use the label created to help sort them out. I can't seem to get the dragging and dropping to work though.
This is my code:
public partial class Form1 : Form
{
private List<Book> books = new List<Book>();
private List<Book> sortedBooks;
private Panel currentPanel;
public Form1()
{
InitializeComponent();
InitializePanels();
}
private void InitializePanels()
{
flowLayoutSender.Controls.Clear();
flowLayoutReceiver.Controls.Clear();
books = GenerateRandomBooks(10);
sortedBooks = new List<Book>(books);
sortedBooks.Sort();
for (int i = 0; i < books.Count; i++)
{
Book book = books[i];
// Create a panel to hold the book information
Panel panel = new Panel
{
Name = "panel" + i,
Width = 50,
Height = 100,
BorderStyle = BorderStyle.FixedSingle
};
Label label = new Label
{
Name = "label" + i,
Text = book.BookNumber,
AutoSize = false,
Width = 50,
Height = 100,
TextAlign = ContentAlignment.MiddleCenter,
Padding = new Padding(0, 30, 0, 0)
};
panel.Controls.Add(label);
panel.MouseDown += Panel_MouseDown;
panel.DragDrop += flowLayoutSender_DragDrop; // Add the DragDrop event handler
flowLayoutSender.Controls.Add(panel);
}
// Add the DragEnter and DragDrop event handlers for flowLayoutSender
flowLayoutSender.DragEnter += flowLayoutSender_DragEnter;
}
private void Panel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
currentPanel = (Panel)sender;
currentPanel.DoDragDrop(currentPanel, DragDropEffects.Move);
}
}
private void flowLayoutSender_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Panel)))
{
e.Effect = DragDropEffects.Move;
}
}
private void flowLayoutSender_DragDrop(object sender, DragEventArgs e)
{
if (currentPanel != null)
{
flowLayoutSender.Controls.Remove(currentPanel);
flowLayoutReceiver.Controls.Add(currentPanel);
currentPanel = null;
}
}
private List<Book> GenerateRandomBooks(int count)
{
List<Book> randomBooks = new List<Book>();
Random random = new Random();
for (int i = 0; i < count; i++)
{
int deweyCategory = random.Next(1, 10) * 100;
int deweyNumber = random.Next(1, 1000);
string bookNumber = $"{deweyCategory}-{deweyNumber:D3}";
Book book = new Book(bookNumber);
randomBooks.Add(book);
}
return randomBooks;
}
private void flowLayoutReceiver_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Panel)))
{
e.Effect = DragDropEffects.Move;
}
}
private void flowLayoutReceiver_DragDrop(object sender, DragEventArgs e)
{
if (currentPanel != null)
{
flowLayoutSender.Controls.Remove(currentPanel);
flowLayoutReceiver.Controls.Add(currentPanel);
currentPanel = null;
}
}
}
But I just cant seem to get the panels to drag and drop, I click and drag panel and nothing happens. Can I get any help pls
The main problem here is that the Labels you're adding to the Panels completely cover their host, so you don't have a MouseDown
event on the Panels.
I've resized the Label and docked them to Top, so the Panels can receive mouse events. Modify as required.
The Panel that's being dragged is the object reference in ObjectData
. You don't need to store this reference.
For sure, you cannot set it to null
, because you set to null
the Control's reference itself.
You also don't need to remove the Control from a Controls
collection before you add it to another. A Control can only have one Parent. When you add it to another Controls
collection, the original one loses the reference.
You only need to handle the Panel's MouseDown
event.
Note: I'm using MouseDown to start the operation, but we should actually handle MouseMove
+ SystemInformation.DragSize as shown here.
The FlowLayoutPanel that hosts the Panels doesn't need to do much here (unless it should also allow to receive back a Panel that was moved).
The FlowLayoutPanel that receives the Panels needs to have its AllowDrop
Property set to true
.
It also needs to handle, at least, the DragEnter
and DragDrop
events.
public Form1() {
InitializeComponent();
flowLayoutSender.SuspendLayout();
for (int i = 0; i < 5; i++) {
// Create a panel to hold the book information
// [...]
Label label = new Label {
Dock = DockStyle.Top,
Size = new Size(50, 30),
Text = book.BookNumber,
TextAlign = ContentAlignment.MiddleCenter,
};
panel.Controls.Add(label);
panel.MouseDown += Panel_MouseDown;
flowLayoutSender.Controls.Add(panel);
}
flowLayoutSender.ResumeLayout(false);
}
private void Panel_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
var panel = sender as Panel;
if (panel is null) return;
panel.DoDragDrop(panel, DragDropEffects.Move);
}
}
private void flowLayoutReceiver_DragEnter(object sender, DragEventArgs e) {
if (e.Data != null && e.Data.GetDataPresent(typeof(Panel))) {
e.Effect = DragDropEffects.Move;
}
else {
e.Effect = DragDropEffects.None;
}
}
private void flowLayoutReceiver_DragDrop(object sender, DragEventArgs e) {
if (e.Data != null && e.Data.GetDataPresent(typeof(Panel))) {
var panel = e.Data.GetData(typeof(Panel)) as Panel;
(sender as Control)?.Controls.Add(panel);
}
}
This is how it works: