因为之前接到的一个需求,让excel的宽度自动适应。所以最近一直在看Excel相关内容,从结构到.net的两个类库OpenXml和Office.Interop.Excel,再到一些具体的使用。
  这次学习花费了很多东西,主要陷入了两个误区,一个是一开始先入为主的认为Openxml中微软肯定有解决方案(我以为功能很简单,而且Interop.Excel是有解决方法的,但是实际上并没有),另一个在style.xml里面陷入误区了(很想当然的认为了自动列宽应该在stylesheet.xml里面),结果好几天都是毫无头绪。好心塞。。。
后来终于找到了可爱的Columns类和Column类,然而。。。仔细阅读,逐个属性、方法的检查之后,居然没有解决方案,Width属性要给具体值(然而当初脑补的有个什么AutoFit()这种名字的方法。。。too naive)。
  后来在StackOverflow上找到了半个答案。大概意思就是:BestFit 属性是信息属性 (可能由 Excel 优化)。开发者仍然需要为该列提供宽度。这意味着你必须实际计算列宽度,根据单元格的内容。打开 XML SDK 并不会自动做宽度匹配。
 
根据官方的文档中BestFit属性给出最后的解决方案如下:
 
  首先得到数据源中每一列的最大值。
列宽单位:一个列宽单位等于一个常规样式中一个字符的宽度,excel里面用像素和宽度来共同描述宽度。
                至于常规样式。。。(工具---选项---常规中的标准字体(当然与字大小也有关))
  上面中间的就是
  顺便说一下像素和厘米的换算吧  这里还要引入一个像素精度的概念dpi,如果显示器的像素精度是96dpi,其实就是96像素每英寸。像素精度是由显示设备的分辨率来的。下面放个截图(磅是行高单位) PS:鼠标上的DPI就是这个概念
 
  在常规样式字体下,列宽度的值是根据0,1,2,...,9这是个字符的平均值或最大值(OpenXml官方文档上给的公式是最大值,网上有人说平均值,具体还要再查一下)来计算的。 每个单元格有 4 个像素的边距填充 (每侧两个),再加上 1 像素填充的网格线。
  列宽度 = Truncate([{字符数} * {最大数字宽度像素} + {4+1个像素}]/{最大数字宽度}*256)/256
[示例: 使用宋体字体为例,11号字体大小的最大单个字符宽度是7个像素在96 dpi时。事实上,每个数字在设置为此字体时是相同的宽度。因此,如果值的宽度是 8 个字符宽,列宽的值也就是 Truncate([8*7+5]/7*256)/256 = 8.7109375个字符宽度]
 
要转化为列宽度的值在运行时 (以像素为单位表示) 的文件中的宽度值,请使用此公式:
= Truncate (((256 * {列宽度} + Truncate(128 / {最大数字宽度})) / 256) * {最大数字宽度})
[示例: 如上使用同一示例,计算将是 Truncate(((256*8.7109375+Truncate(128/7))/256)*7) = 61 像素。]
 
若要将像素转换为字符数,请使用此公式:
= Truncate(({像素数}-5) / {最大数字宽度像素} * 100 + 0.5) / 100
 
最后给出一个Demo
 using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet; namespace OpenXmlGenerateExcelTest
{
class Program
{
static void Main()
{
CreateSpreadSheet();
} private static void CreateSpreadSheet()
{
string fileName = "X:\\01.xlsx";
string sheetName = "测试表格sheet—1";
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook))
{
spreadSheet.AddWorkbookPart();
spreadSheet.WorkbookPart.Workbook = new Workbook(); WorksheetPart worksheetPart1 = spreadSheet.WorkbookPart.AddNewPart<WorksheetPart>();
worksheetPart1.Worksheet = new Worksheet();
SheetData sheetData = new SheetData();
ProductData(sheetData);
worksheetPart1.Worksheet.AppendChild(AutoFit(sheetData));
worksheetPart1.Worksheet.AppendChild(sheetData); spreadSheet.WorkbookPart.WorksheetParts.ElementAt().Worksheet.Save(); spreadSheet.WorkbookPart.Workbook.AppendChild(new Sheets());
spreadSheet.WorkbookPart.Workbook.GetFirstChild<Sheets>().AppendChild(new Sheet()
{
Id = spreadSheet.WorkbookPart.GetIdOfPart(spreadSheet.WorkbookPart.WorksheetParts.First()),
SheetId = ,
Name = sheetName
}); spreadSheet.WorkbookPart.Workbook.Save();
}
} private static void ProductData(SheetData sheetData)
{
for (uint rowIndex = ; rowIndex < ; rowIndex++)
{
Row row = new Row() { RowIndex = rowIndex };
for (char cellIndex = 'A'; cellIndex < 'F'; cellIndex++)
{
Cell cell = new Cell();
string innerText = "";
cell.CellValue = new CellValue(innerText);
cell.DataType = new EnumValue<CellValues>(CellValues.String);
row.Append(cell);
}
for (char cellIndex = 'F'; cellIndex < 'K'; cellIndex++)
{
Cell cell = new Cell();
string innerText = "";
cell.CellValue = new CellValue(innerText);
cell.DataType = new EnumValue<CellValues>(CellValues.String);
row.Append(cell);
}
sheetData.Append(row);
}
} private static Columns AutoFit(SheetData sheetData)
{
var maxColWidth = GetMaxCharacterWidth(sheetData); Columns columns = new Columns(); double maxWidth = ;
foreach (var item in maxColWidth)
{
/*三种单位宽度公式*/
double width = Math.Truncate((item.Value * maxWidth + ) / maxWidth * ) / ;
double pixels = Math.Truncate((( * width + Math.Truncate( / maxWidth)) / ) * maxWidth);
double charWidth = Math.Truncate((pixels - ) / maxWidth * + 0.5) / ; Column col = new Column() { BestFit = true, Min = (UInt32)(item.Key + ), Max = (UInt32)(item.Key + ), CustomWidth = true, Width = (DoubleValue)width };
columns.Append(col);
}
return columns;
} private static Dictionary<int, int> GetMaxCharacterWidth(SheetData sheetData)
{
Dictionary<int, int> maxColWidth = new Dictionary<int, int>();
var rows = sheetData.Elements<Row>();
foreach (var r in rows)
{
var cells = r.Elements<Cell>().ToArray();
for (int i = ; i < cells.Length; i++)
{
var cell = cells[i];
var cellValue = cell.CellValue == null ? string.Empty : cell.CellValue.InnerText;
var cellTextLength = cellValue.Length;
if (maxColWidth.ContainsKey(i))
{
var current = maxColWidth[i];
if (cellTextLength > current)
{
maxColWidth[i] = cellTextLength;
}
}
else
{
maxColWidth.Add(i, cellTextLength);
}
}
}
return maxColWidth;
}
}
}

关于OpenXml SpreadSheet列宽根据内容的Auto-suitability的更多相关文章

  1. 转!!Java JTable 根据表格内容 自动调整表格列宽

    //根据表格内容 自动调整列宽http://blog.sina.com.cn/s/blog_5e54d6140100s1d3.html

  2. MS WORD 表格自动调整列宽,自动变漂亮,根据内容自动调整 .

    在MS WORD中,当有大量的表格出现时,调整每个表格的的高和宽和大小将是一件非常累的事情,拖来拖去,非常耗时间,而且当WORD文档达到300页以上时,调整反应非常的慢,每次拖拉线后,需要等待一段时间 ...

  3. MS WORD 表格自己主动调整列宽,自己主动变美丽,依据内容自己主动调整

    在MS WORD中,当有大量的表格出现时,调整每一个表格的的高和宽和大小将是一件很累的事情,拖来拖去,很耗时间,并且当WORD文档达到300页以上时,调整反应很的慢,每次拖拉线后,须要等待一段时间其才 ...

  4. easyui datagrid 列的内容超出所定义的列宽时,自动换行

    定义表单  nowrap="false"可以使得列中的内容超出所定义的列宽是就会自动换行pagination : true, // 当true时在DataGrid底部显示一个分页工 ...

  5. Delphi xe8 FMX StringGrid根据内容自适应列宽。

    Delphi xe8 FMX StringGrid根据内容自适应列宽. 网上的资料比较复杂,而且不是根据字体字号等设置列宽.故自己写了个function来用. function GetColMaxDa ...

  6. WPF学习笔记(3):ListView根据内容自动调整列宽

    DataGrid中,只要不设置DataGrid的宽度和列宽度,或者将宽度设置为Auto,那么表格就会根据内容自动调整宽度,以显示所有内容.但如果是ListView,按以上方法设置,却达不到列宽自动调整 ...

  7. c# listView中列宽随列中的内容自动调整

    1.创建一个类 ListViewAutoChange  作用:自动调整ListView的列宽 代码如下:(内容很容易理解,没加注释) using System; using System.Collec ...

  8. excel 根据单元格内容自动调整列宽

      excel 根据单元格内容自动调整列宽 CreateTime--2018年5月28日08:49:40 Author:Marydon 1.情景展示 单元格宽度超过了列宽 2.解决方案 第一步:同时选 ...

  9. 使用datatables实现列宽设置、水平滚动条、显示某列部分内容

    示例 1.//使用 columnDefs 给列设置宽度 $('#example').DataTable( { "columnDefs": [ //给第一列指定宽度为表格整个宽度的2 ...

随机推荐

  1. 【特殊的图+DP】【11月校赛】大家一起玩游戏

    大家一起玩游戏 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submi ...

  2. mysql跟踪提交的SQL语句

    http://www.cnblogs.com/wuyifu/p/3328024.html

  3. Foundation--NSString+NSMutableString

    NSString 字符串创建: 1.NSString *strr = @"0123456789"; 2.NSString *str = [NSString stringWithSt ...

  4. MySql优化-你的SQL命中索引了吗

    在项目开发中SQL是必不可少的,表索也一样.这些SQL的运行性能不知道吗?有多少是命中了索引的?命中哪个索引?索引中有哪个是无效索引?这些无效索引是否会影响系统的性能?带着这些问题我们一起来学习一下. ...

  5. MySQL数据库改名字

    在这里首先感谢那个网上已经给出了解决办法的同志 有很多MySQL数据库的初学者可能都会遇到一个关于改名字的问题,可能大家第一时间就会想到去网上搜搜,其实我跟大家的心理是一样的(呵呵). 据我所知,My ...

  6. 向Oracle数据库中CLOB插入数据报错问题

    今天在项目中向数据库的CLOB属性插入一段篇文章(1000~2000)字就会报一个字符串过长的错误. 网上说用流来处理,没有这么做.这像是一个Bug,只要把插入的数据,默认扩充到2000以上就ok了. ...

  7. Python之路第七天,基础(9)-面向对象(上)

    面向对象的编程思想 回想 我们所学过的编程方法: 面向过程:根据业务逻辑从上到下写堆叠代码. 函数式编程:将重复的代码封装到函数中,只需要写一遍,之后仅调用函数即可. 面向过程编程最易被初学者接受,其 ...

  8. Holding Bin-Laden Captive!(hdoj1085)代码并未完全看懂

    We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But rec ...

  9. C语言学习second--C语言基础学习

    1.标准C语言 C语言诞生于20世纪70年代,年龄比我们自己还要大,期间产生了很多标准,但是各种编译器对标准的支持不尽相同. ANSI C是使用的最广泛的一个标准,也是第一个正式标准,被称为“标准C语 ...

  10. mvc学习总结-使用Ninject和CodeFirst

    1.Ninject用来解耦程序:即对接口编程,而不是对实现类编程:理解:BLL对IDAL编程,对应的是调用多种数据实现的DAL,DAL可以是SqlServer的,可以是Oracle,或其他数据媒介: ...