/// <summary> /// Computes the optimal size for all columns in a table /// and return an array of widths in pixels /// </summary> /// <param name="table">table to compute</param> /// <param name="preferredWidth">desired width (pixels) to fit in</param> /// <returns></returns> public int[] GetColumnSizes(DataTable table, int preferredWidth) { var columns = table.Columns.Count; var width = preferredWidth; var maxText = new int[columns]; // max. text width over all rows var maxWord = new int[columns]; // max. width of longest word var isFlex = new bool[columns]; // is column flexible? var canWrap = new bool[columns]; // can column be wrapped? var colw = new int[columns]; // final width of columns for (var r = 0; r < table.Rows.Count; r++) { var row = table.Rows[r]; for (var i = 0; i < columns; i++) { var args = new MeasureCellEventArgs(r, i, DefaultFont, DefaultCellPadding); OnMeasuringCell(args); var cell = string.Format("{0}", row[i]); var pad = 2 * args.CellPadding; maxText[i] = args.MaxTextWidth >= 0 ? args.MaxTextWidth : Math.Max(maxText[i], PixelRuler.MeasureString(cell, args.CellFont, pad)); if (args.MaxWordWidth >= 0) { maxWord[i] = args.MaxWordWidth; } else { if (PixelRuler.CanWrap(cell)) { canWrap[i] = true; maxWord[i] = Math.Max(maxWord[i], PixelRuler.MeasureWord(cell, args.CellFont, pad)); } else { maxWord[i] = maxText[i]; } } } var left = width - (columns - 1) * TableBorderSize; var avg = left / columns; var nflex = 0; // Determine whether columns should be flexible and assign width of non-flexible cells for (var i = 0; i < columns; i++) { isFlex[i] = maxText[i] > 2 * avg; if (isFlex[i]) { nflex++; } else { colw[i] = maxText[i]; left -= colw[i]; } } // if there is not enough space, make columns that could be word-wrapped flexible, too if (left < nflex * avg) { for (var i = 0; i < columns; i++) { if (!isFlex[i] && canWrap[i]) { left += width; //??? colw[i] = 0; isFlex[i] = true; nflex += 1; } } } // Calculate weights for flexible columns. The max width is capped at the page width // to treat columns that have to be wrapped more or less equal var tot = 0; for (var i = 0; i < columns; i++) { if (isFlex[i]) { maxText[i] = Math.Min(maxText[i], width); tot += maxText[i]; } } // Assign the actual width for flexible columns. // Make sure that it is at least as long as the longest word length for (var i = 0; i < columns; i++) { if (isFlex[i]) { if (tot > 0) { colw[i] = left * maxText[i] / tot; } colw[i] = Math.Max(colw[i], maxWord[i]); left -= colw[i]; } } } return(colw); }
private void OnMeasuringCell(MeasureCellEventArgs e) { MeasuringCell?.Invoke(this, e); }