博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于OpenXml SpreadSheet列宽根据内容的Auto-suitability
阅读量:4323 次
发布时间:2019-06-06

本文共 6154 字,大约阅读时间需要 20 分钟。

      因为之前接到的一个需求,让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
1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using DocumentFormat.OpenXml;  5 using DocumentFormat.OpenXml.Packaging;  6 using DocumentFormat.OpenXml.Spreadsheet;  7   8 namespace OpenXmlGenerateExcelTest  9 { 10     class Program 11     { 12         static void Main() 13         { 14             CreateSpreadSheet(); 15         } 16  17         private static void CreateSpreadSheet() 18         { 19             string fileName = "X:\\01.xlsx"; 20             string sheetName = "测试表格sheet—1"; 21             using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook)) 22             { 23                 spreadSheet.AddWorkbookPart(); 24                 spreadSheet.WorkbookPart.Workbook = new Workbook(); 25  26                 WorksheetPart worksheetPart1 = spreadSheet.WorkbookPart.AddNewPart
(); 27 worksheetPart1.Worksheet = new Worksheet(); 28 SheetData sheetData = new SheetData(); 29 ProductData(sheetData); 30 worksheetPart1.Worksheet.AppendChild(AutoFit(sheetData)); 31 worksheetPart1.Worksheet.AppendChild(sheetData); 32 33 spreadSheet.WorkbookPart.WorksheetParts.ElementAt(0).Worksheet.Save(); 34 35 spreadSheet.WorkbookPart.Workbook.AppendChild(new Sheets()); 36 spreadSheet.WorkbookPart.Workbook.GetFirstChild
().AppendChild(new Sheet() 37 { 38 Id = spreadSheet.WorkbookPart.GetIdOfPart(spreadSheet.WorkbookPart.WorksheetParts.First()), 39 SheetId = 1, 40 Name = sheetName 41 }); 42 43 spreadSheet.WorkbookPart.Workbook.Save(); 44 } 45 } 46 47 private static void ProductData(SheetData sheetData) 48 { 49 for (uint rowIndex = 1; rowIndex < 5; rowIndex++) 50 { 51 Row row = new Row() { RowIndex = rowIndex }; 52 for (char cellIndex = 'A'; cellIndex < 'F'; cellIndex++) 53 { 54 Cell cell = new Cell(); 55 string innerText = "12234433433"; 56 cell.CellValue = new CellValue(innerText); 57 cell.DataType = new EnumValue
(CellValues.String); 58 row.Append(cell); 59 } 60 for (char cellIndex = 'F'; cellIndex < 'K'; cellIndex++) 61 { 62 Cell cell = new Cell(); 63 string innerText = "12234"; 64 cell.CellValue = new CellValue(innerText); 65 cell.DataType = new EnumValue
(CellValues.String); 66 row.Append(cell); 67 } 68 sheetData.Append(row); 69 } 70 } 71 72 private static Columns AutoFit(SheetData sheetData) 73 { 74 var maxColWidth = GetMaxCharacterWidth(sheetData); 75 76 Columns columns = new Columns(); 77 78 double maxWidth = 7; 79 foreach (var item in maxColWidth) 80 { 81 /*三种单位宽度公式*/ 82 double width = Math.Truncate((item.Value * maxWidth + 5) / maxWidth * 256) / 256; 83 double pixels = Math.Truncate(((256 * width + Math.Truncate(128 / maxWidth)) / 256) * maxWidth); 84 double charWidth = Math.Truncate((pixels - 5) / maxWidth * 100 + 0.5) / 100; 85 86 Column col = new Column() { BestFit = true, Min = (UInt32)(item.Key + 1), Max = (UInt32)(item.Key + 1), CustomWidth = true, Width = (DoubleValue)width }; 87 columns.Append(col); 88 } 89 return columns; 90 } 91 92 private static Dictionary
GetMaxCharacterWidth(SheetData sheetData) 93 { 94 Dictionary
maxColWidth = new Dictionary
(); 95 var rows = sheetData.Elements
(); 96 foreach (var r in rows) 97 { 98 var cells = r.Elements
().ToArray(); 99 for (int i = 0; i < cells.Length; i++)100 {101 var cell = cells[i];102 var cellValue = cell.CellValue == null ? string.Empty : cell.CellValue.InnerText;103 var cellTextLength = cellValue.Length;104 if (maxColWidth.ContainsKey(i))105 {106 var current = maxColWidth[i];107 if (cellTextLength > current)108 {109 maxColWidth[i] = cellTextLength;110 }111 }112 else113 {114 maxColWidth.Add(i, cellTextLength);115 }116 }117 }118 return maxColWidth;119 }120 }121 }
View Code

 

转载于:https://www.cnblogs.com/sunxingege/p/4905262.html

你可能感兴趣的文章
MYSQL GTID使用运维介绍(转)
查看>>
04代理,迭代器
查看>>
解决Nginx+PHP-FPM出现502(Bad Gateway)错误问题
查看>>
Java 虚拟机:互斥同步、锁优化及synchronized和volatile
查看>>
2.python的基本数据类型
查看>>
python学习笔记-day10-01-【 类的扩展: 重写父类,新式类与经典的区别】
查看>>
查看端口被占用情况
查看>>
浅谈css(块级元素、行级元素、盒子模型)
查看>>
Ubuntu菜鸟入门(五)—— 一些编程相关工具
查看>>
PHP开源搜索引擎
查看>>
12-FileZilla-响应:550 Permission denied
查看>>
ASP.NET MVC 3 扩展生成 HTML 的 Input 元素
查看>>
LeetCode 234. Palindrome Linked List
查看>>
编译HBase1.0.0-cdh5.4.2版本
查看>>
结构体指针
查看>>
迭代器
查看>>
Food HDU - 4292 (结点容量 拆点) Dinic
查看>>
Ubuntu安装Sun JDK及如何设置默认java JDK
查看>>
[经典算法] 排列组合-N元素集合的M元素子集
查看>>
Codeforces 279D The Minimum Number of Variables 状压dp
查看>>