flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Clicking a Specific Cell in a TableLayoutPanel

Sunday, August 24, 2008 8:02 PM

TableLayoutPanels are a great device for automatically laying out complicated WinForms UIs.  One thing they can also be useful for, is as a docking pane for a user to drag objects onto and then automatically drop into place.  However, to do this we have to know which cell of a TableLayoutPanel a user has dragged an item onto. 

To do this, simply query the user's mouse position relative to the panel and iterate the rows and columns of the panel manually checking whether or not the mouse position falls within each row's or column's boundaries.  You can get the mouse position from most mouse related events such as MouseClicks, or MouseDowns.  In the example below, I iterate through each row and column until I find the matching row or column...

private static TableLayoutPanelCellPosition CalculateDropCellPosition(Point coordsOnTableLayoutPanel,
                                                               TableLayoutPanel targetTableLayoutPanel)
{
    var cellPosition = new TableLayoutPanelCellPosition();
    for (var rowNumber = 0; rowNumber < targetTableLayoutPanel.RowCount; rowNumber++)
    {
        if (targetTableLayoutPanel.RowStyles[rowNumber].SizeType == SizeType.Percent)
        {
            if (IsYCoordinateOverRow(coordsOnTableLayoutPanel.Y, rowNumber, 
                    targetTableLayoutPanel.RowStyles[rowNumber].Height, targetTableLayoutPanel.Height))
            {
                cellPosition.Row = rowNumber;
                break;
            }
        }
    }
    for (var columNumber = 0; columNumber < targetTableLayoutPanel.ColumnCount; columNumber++)
    {
        if (targetTableLayoutPanel.ColumnStyles[columNumber].SizeType == SizeType.Percent)
        {
            if (IsXCoordinateOverColumn(coordsOnTableLayoutPanel.X, columNumber,
                    targetTableLayoutPanel.ColumnStyles[columNumber].Width, targetTableLayoutPanel.Width))
            {
                cellPosition.Column = columNumber;
                break;
            }
        }
    }
    return cellPosition;
}

 

The IsXCoordinateOverColumn() and IsYCoordinateOverRow() methods actually perform the manual hit test to determine whether or not the given point falls within the given row or column...

private static bool IsXCoordinateOverColumn(int xCoordinate, int columNumber, float columnWidth, int tableWidth)
{
    var trueHeight = (columnWidth*0.01)*tableWidth;
    var startingPoint = columNumber*trueHeight;
 
    var coordinateIsOverColumn = false;
    if ((xCoordinate > startingPoint) && (xCoordinate < (startingPoint + trueHeight)))
        coordinateIsOverColumn = true;
 
    return coordinateIsOverColumn;
}

 

The above code only works for layout panels where the SizeType equals Percent, however, a SizeType of Absolute would actually be much simpler since we could simply determine whether or not the given coordinate falls within a given range instead of having to compensate for the controls actual height and width as we are above.

You can download the sample code from here.  To use it, simply build and run the application and drag any file from your desktop into one of the panes of the application.


Feedback

 re: Clicking a Specific Cell in a TableLayoutPanel

I've downloaded your code and it works grea. However, when I try and duplicate it in my project I cannot drop an object into my tablelayout panel. I've looked at everything and it is the same. Any suggestion.

Thanks
Baffled 9/8/2008 9:27 PM | Gregor

 re: Clicking a Specific Cell in a TableLayoutPanel

Thanks again for the code and I appreciate your feedback. The problem I was having was a result of running VS as administrator on my Vista OS. This bug goes back to VS 2005 and Vista. There might be a fix to it; but I haven't looked for it.
9/11/2008 5:14 PM | Gregor

# re: Clicking a Specific Cell in a TableLayoutPanel

Thanks for the udpate, Gregor! 9/12/2008 8:31 AM | Jeremy

Post a comment





 

Please add 3 and 7 and type the answer here: