我编写了一个使用OpenXML生成Excel文件的代码。 下面是在Excel中生成列的代码。
Worksheet worksheet = new Worksheet();
Columns columns = new Columns();
int numCols = dt1.Columns.Count;
for (int col = 0; col < numCols; col++)
{
Column c = CreateColumnData((UInt32)col + 1, (UInt32)numCols + 1, 20.42578125D);
columns.Append(c);
}
worksheet.Append(columns);
另外,我尝试在line下创建列。
Column c = new Column
{
Min = (UInt32Value)1U,
Max = (UInt32Value)1U,
Width = 25.42578125D,
BestFit = true,
CustomWidth = true
};
我认为使用BestFit
它应该有效。但它没有设置自动尺寸。
答案 0 :(得分:14)
不幸的是,你必须自己计算
这就是我所拥有的。它适用于我的数据表格,其中包含一些额外的代码来处理我设置的一些样式。它无论如何都不完美,但却能满足我的需要。
private WorksheetPart mySheetPart;
private void WriteToTable()
{
//Get your sheet data - write Rows and Cells
SheetData sheetData = GetSheetData();
//get your columns (where your width is set)
Columns columns = AutoSize(sheetData);
//add to a WorksheetPart.WorkSheet
mySheetPart.Worksheet = new Worksheet();
mySheetPart.Worksheet.Append(columns);
mySheetPart.Worksheet.Append(sheetData);
}
private Columns AutoSize(SheetData sheetData)
{
var maxColWidth = GetMaxCharacterWidth(sheetData);
Columns columns = new Columns();
//this is the width of my font - yours may be different
double maxWidth = 7;
foreach (var item in maxColWidth)
{
//width = Truncate([{Number of Characters} * {Maximum Digit Width} + {5 pixel padding}]/{Maximum Digit Width}*256)/256
double width = Math.Truncate((item.Value * maxWidth + 5) / maxWidth * 256) / 256;
//pixels=Truncate(((256 * {width} + Truncate(128/{Maximum Digit Width}))/256)*{Maximum Digit Width})
double pixels = Math.Truncate(((256 * width + Math.Truncate(128 / maxWidth)) / 256) * maxWidth);
//character width=Truncate(({pixels}-5)/{Maximum Digit Width} * 100+0.5)/100
double charWidth = Math.Truncate((pixels - 5) / maxWidth * 100 + 0.5) / 100;
Column col = new Column() { BestFit = true, Min = (UInt32)(item.Key + 1), Max = (UInt32)(item.Key + 1), CustomWidth = true, Width = (DoubleValue)width };
columns.Append(col);
}
return columns;
}
private Dictionary<int, int> GetMaxCharacterWidth(SheetData sheetData)
{
//iterate over all cells getting a max char value for each column
Dictionary<int, int> maxColWidth = new Dictionary<int, int>();
var rows = sheetData.Elements<Row>();
UInt32[] numberStyles = new UInt32[] { 5, 6, 7, 8 }; //styles that will add extra chars
UInt32[] boldStyles = new UInt32[] { 1, 2, 3, 4, 6, 7, 8 }; //styles that will bold
foreach (var r in rows)
{
var cells = r.Elements<Cell>().ToArray();
//using cell index as my column
for (int i = 0; i < cells.Length; i++)
{
var cell = cells[i];
var cellValue = cell.CellValue == null ? string.Empty : cell.CellValue.InnerText;
var cellTextLength = cellValue.Length;
if (cell.StyleIndex != null && numberStyles.Contains(cell.StyleIndex))
{
int thousandCount = (int)Math.Truncate((double)cellTextLength / 4);
//add 3 for '.00'
cellTextLength += (3 + thousandCount);
}
if (cell.StyleIndex != null && boldStyles.Contains(cell.StyleIndex))
{
//add an extra char for bold - not 100% acurate but good enough for what i need.
cellTextLength += 1;
}
if (maxColWidth.ContainsKey(i))
{
var current = maxColWidth[i];
if (cellTextLength > current)
{
maxColWidth[i] = cellTextLength;
}
}
else
{
maxColWidth.Add(i, cellTextLength);
}
}
}
return maxColWidth;
}
答案 1 :(得分:7)
BestFit属性是一个信息属性(可能由Excel优化)。您仍需要提供列的宽度。这意味着您必须根据单元格内容实际计算列宽。 Open XML SDK不会自动为您执行此操作,因此最好为此使用第三方库。
答案 2 :(得分:1)
我没有时间去研究它,但我没有发表评论而是a link,而是认为我会分享一些似乎对此做过一些研究的人的评论。
我个人遇到了让the official formulas符合现实的问题。即短字符串的单元格太小,字符串越长,单元格越大,最重要的是,Excel中显示的值与我在DocumentFormat.OpenXml.Spreadsheet.Column
的{{1}} - 属性中插入的值成比例地小。我的快速解决方案就是拥有最小宽度。
无论如何,这是评论:
我最终必须这样做,因为我感兴趣的xlsx文件是自动生成的,一旦打开它们应该看起来很好所以我进一步研究了这一点,发现有一些问题需要准确在Excel中调整列的大小。
需要使用准确的字符大小调整,这意味着您需要使用MeasureCharacterRanges而不是使用MeasureString,请参阅http://groups.google.com/group/microsoft.public.office.developer.com.add_ins/browse_thread/thread/2fc33557feb72ab4/adaddc50480b8cff?lnk=raot
- 醇>
尽管规格说要添加5个像素(1个用于边框,2个用于每个边距),Excel似乎使用9 - 1作为边框,5个作为前导空格,3个作为尾部空格 - 我只通过使用辅助功能应用程序找到了这个。放大镜和使用Excel自动调整列后计算像素
实际上我的计算基于底层字体指标,所以我实际上并没有使用MeasureCharacterRanges或MeasureString。如果有人对字体指标感兴趣,那么:
Width
{MaxDigitWidth}是一个四舍五入到96 dpi的0..9位数的最近像素的整数 {DesiredWidth}是将所有字符宽度加在一起的总和,其中每个字符宽度是96 dpi处字符宽度四舍五入到最接近的整数。请注意,每个字符都是四舍五入而不是总和
答案 3 :(得分:1)
我终于找到了一个解决方案,它使用图形引擎 GDI+ 来准确地做到这一点。 avg. char width * number of chars
永远不会削减它。
这里有一个警告,如果您的目标平台是 linux,您将需要几个库 - 一个用于 GDI+ 互操作,另一个用于添加开放的 microsoft web 字体。
它使用像素的基本单位,考虑到 excel 字体是 pt
和列宽 INCHES! (笑)
这是方法。它需要一个 JSchema 来映射到列,但你明白了要点。
private static Columns CreateColumnDefs(JSchema jsonSchema)
{
const double cellPadding = .4;
const double minCellWidth = 10;
var columnDefs = new Columns();
var columnIndex = 0U;
// set up graphics for calculating column width based on heading text width
var bmp = new Bitmap(1, 1);
// todo: ensure linux host has gdi and "Microsoft core fonts" libs installed
using var graphics = Graphics.FromImage(bmp);
graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
graphics.PageUnit = GraphicsUnit.Pixel;
// excel fonts are in points - Arial 10pt matches the excel default of Calibri 11pt pretty well...
using var font = new Font("Arial", 10F, FontStyle.Bold, GraphicsUnit.Point);
// currently only handles 1 level (no nested objects)
foreach (var (_, value) in jsonSchema.Properties)
{
var pixelWidth = graphics.MeasureString(value.Title, font).Width;
// see: https://stackoverflow.com/questions/7716078/formula-to-convert-net-pixels-to-excel-width-in-openxml-format/7902415
var openXmlWidth = (pixelWidth - 12 + 5) / 7d + 1; // from pixels to inches.
columnIndex++;
var column = new Column
{
BestFit = true,
CustomWidth = true,
Width = Math.Max(openXmlWidth + cellPadding, minCellWidth),
Min = columnIndex,
Max = columnIndex
};
columnDefs.Append(column);
}
return columnDefs;
}
编辑
要在 linux 上运行安装,例如:
RUN apt update && apt-get install -y libgdiplus
(我不需要任何额外的字体库,所以也许系统字体可以工作)
答案 4 :(得分:0)
这里是可能的公式 width =截断([{字符数}} * {最大数字宽度} + {5像素填充}] / {最大数字宽度} * 256)/ 256
答案 5 :(得分:0)
@Mittal Patel看看我的answer。发布的代码使用DOM方法,但是我也使用SAX方法创建了一个解决方案,并且结果非常出色-没有内存消耗(直接从DataReader写入),并且比Interop库快得多。自动调整功能是唯一的缺点-您必须两次读取相同的数据。