I, like most, am new to Open XML. I was trying to find a way to size the column to my largest item. I mostly found that the current spec doesn't support it automatically. After poking around I found a formula which I rework to calculate the width based on the pixel width of the string. I then found a way to size the column.
Here is the complete source code to do it. I should mention that I am NOT searching for the largest string in the column but rather calculating 1 item. Haven't quite figured out how to do search yet.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace AutoFit
{
class Program
{
static void Main(string[] args)
{
string docName = @"D:\Temp\MyFirstExcel.xlsx";
// Create a Wordprocessing document.
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(docName, SpreadsheetDocumentType.Workbook))
{
// Add a WorkbookPart to the document.
WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
// ####################################
// IMPORTANT STUFF
// ####################################
string strText = "This is some really, really long text to display.";
double width = GetWidth("Calibri", 11, strText);
string strText2 = "123";
double width2 = GetWidth("Calibri", 11, strText2);
Columns columns = new Columns();
columns.Append(CreateColumnData(2, 2, width));
columns.Append(CreateColumnData(3, 3, width2));
worksheetPart.Worksheet.Append(columns);
// ####################################
// END OF IMPORTANT STUFF
// ####################################
SheetData sd = new SheetData();
worksheetPart.Worksheet.Append(sd);
// Add Sheets to the Workbook.
Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
// Append a new worksheet and associate it with the workbook.
Sheet sheet = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "mySheet"
};
sheets.Append(sheet);
// Add Data
Row row = new Row();
Cell cell;
// String
cell = CreateSpreadsheetCellIfNotExist(worksheetPart.Worksheet, "B2");
cell.CellValue = new CellValue(strText);
cell.DataType = CellValues.String;
// Number
int count = 123;
cell = CreateSpreadsheetCellIfNotExist(worksheetPart.Worksheet, "C2");
CellValue cellValue = new CellValue(count.ToString());
cell.CellValue = cellValue;
cell.DataType = CellValues.Number;
workbookpart.Workbook.Save();
// Close the document.
spreadsheetDocument.Close();
}
}
private static double GetWidth(string font, int fontSize, string text)
{
System.Drawing.Font stringFont = new System.Drawing.Font(font, fontSize);
return GetWidth(stringFont, text);
}
private static double GetWidth(System.Drawing.Font stringFont, string text)
{
// This formula is based on this article plus a nudge ( + 0.2M )
// http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column.width.aspx
// Truncate(((256 * Solve_For_This + Truncate(128 / 7)) / 256) * 7) = DeterminePixelsOfString
Size textSize = TextRenderer.MeasureText(text, stringFont);
double width = (double)(((textSize.Width / (double)7) * 256) - (128 / 7)) / 256;
width = (double)decimal.Round((decimal)width + 0.2M, 2);
return width;
}
private static Column CreateColumnData(UInt32 StartColumnIndex, UInt32 EndColumnIndex, double ColumnWidth)
{
Column column;
column = new Column();
column.Min = StartColumnIndex;
column.Max = EndColumnIndex;
column.Width = ColumnWidth;
column.CustomWidth = true;
return column;
}
// Given a Worksheet and a cell name, verifies that the specified cell exists.
// If it does not exist, creates a new cell.
private static Cell CreateSpreadsheetCellIfNotExist(Worksheet worksheet, string cellName)
{
string columnName = GetColumnName(cellName);
uint rowIndex = GetRowIndex(cellName);
IEnumerable<Row> rows = worksheet.Descendants<Row>().Where(r => r.RowIndex.Value == rowIndex);
Cell cell;
// If the Worksheet does not contain the specified row, create the specified row.
// Create the specified cell in that row, and insert the row into the Worksheet.
if (rows.Count() == 0)
{
Row row = new Row() { RowIndex = new UInt32Value(rowIndex) };
cell = new Cell() { CellReference = new StringValue(cellName) };
row.Append(cell);
worksheet.Descendants<SheetData>().First().Append(row);
worksheet.Save();
}
else
{
Row row = rows.First();
IEnumerable<Cell> cells = row.Elements<Cell>().Where(c => c.CellReference.Value == cellName);
// If the row does not contain the specified cell, create the specified cell.
if (cells.Count() == 0)
{
cell = new Cell() { CellReference = new StringValue(cellName) };
row.Append(cell);
worksheet.Save();
}
else
cell = cells.First();
}
return cell;
}
// Given a cell name, parses the specified cell to get the column name.
private static string GetColumnName(string cellName)
{
// Create a regular expression to match the column name portion of the cell name.
Regex regex = new Regex("[A-Za-z]+");
Match match = regex.Match(cellName);
return match.Value;
}
// Given a cell name, parses the specified cell to get the row index.
private static uint GetRowIndex(string cellName)
{
// Create a regular expression to match the row index portion the cell name.
Regex regex = new Regex(@"\d+");
Match match = regex.Match(cellName);
return uint.Parse(match.Value);
}
}
}