Microsoft has finally aired the first ad of the new campaign that will make Windows cool again and save us all who have hitched our careers to .NET.
Apparently we're all screwed.
I love the fact that a book dedicated to making WinForms do what you want has a picture of not 1, but 2 crowbars on the cover.
At least we're finally being honest with ourselves.
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.