Question

I have a tableLayoutPanel with 16 cells. 15 of the cells have controls. I want to be able to move the controls from one cell to another at runtime.

I have used

    private void button15_Click(object sender, EventArgs e)
    {
        tableLayoutPanel1.Controls.Remove(button15);

        tableLayoutPanel1.Controls.Add(button15, 3, 3);
    }

This works well but i want to know if there is any better way to do this???

Was it helpful?

Solution

In Winforms, you can only move a control inside its parent (of course there are some exceptions to some controls which in fact don't have any Parent). So the idea here is if you want to move a control of your TableLayoutPanel, you have to set its Parent to your Form of another container when mouse is held down, when moving, the position of the control is in the new parent, after mouse is released, we have to set the Parent of the control to the TableLayoutPanel back, of course we have to find the drop-down cell position and use SetCellPosition method to position the control on the TableLayoutPanel, here is the demo code for you (works great), I use 2 Buttons in this demo, you can replace them with any control you want:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
        //This will prevent flicker
        typeof(TableLayoutPanel).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(tableLayoutPanel1, true, null);
    }
    Point downPoint;
    bool moved;
    //This is used to store the CellBounds together with the Cell position
    //so that we can find the Cell position later (after releasing mouse).
    Dictionary<TableLayoutPanelCellPosition, Rectangle> dict = new Dictionary<TableLayoutPanelCellPosition, Rectangle>();
    //MouseDown event handler for all your controls (on the tableLayoutPanel1)
    private void Buttons_MouseDown(object sender, MouseEventArgs e) {
        Control button = sender as Control;
        button.Parent = this;            
        button.BringToFront();            
        downPoint = e.Location;            
    }
    //MouseMove event handler for all your controls (on the tableLayoutPanel1)
    private void Buttons_MouseMove(object sender, MouseEventArgs e) {
        Control button = sender as Control;
        if (e.Button == MouseButtons.Left) {
            button.Left += e.X - downPoint.X;
            button.Top += e.Y - downPoint.Y;
            moved = true;
            tableLayoutPanel1.Invalidate();
        }
    }
    //MouseUp event handler for all your controls (on the tableLayoutPanel1)
    private void Buttons_MouseUp(object sender, MouseEventArgs e) {
        Control button = sender as Control;
        if (moved) {
            SetControl(button, e.Location);
            button.Parent = tableLayoutPanel1;
            moved = false;
        }
    }
    //This is used to set the control on the tableLayoutPanel after releasing mouse
    private void SetControl(Control c, Point position) {
        Point localPoint = tableLayoutPanel1.PointToClient(c.PointToScreen(position));
        var keyValue = dict.FirstOrDefault(e => e.Value.Contains(localPoint));
        if (!keyValue.Equals(default(KeyValuePair<TableLayoutPanelCellPosition, Rectangle>))) {
            tableLayoutPanel1.SetCellPosition(c, keyValue.Key);
        }
    }
    //CellPaint event handler for your tableLayoutPanel1
    private void tableLayoutPanel1_CellPaint(object sender, TableLayoutCellPaintEventArgs e) {
        dict[new TableLayoutPanelCellPosition(e.Column, e.Row)] = e.CellBounds;
        if (moved) {
            if (e.CellBounds.Contains(tableLayoutPanel1.PointToClient(MousePosition))) {
                e.Graphics.FillRectangle(Brushes.Yellow, e.CellBounds);
            }
        }
    }
}

enter image description here

OTHER TIPS

Remove Lock & set dock to none and move!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top