2013-08-16 244 views
10

我已經編寫了使用OpenXML生成Excel文件的代碼。 下面是在Excel中生成列的代碼。OpenXML: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); 

此外,我嘗試在下面的行創建列。

Column c = new Column() { Min = (UInt32Value)1U, Max = (UInt32Value)1U, Width = 25.42578125D, BestFit = true, CustomWidth = true}; 

我以爲使用BestFit它應該工作。但它不會設置自動大小。

請幫我解決這個問題。

謝謝

回答

7

BestFit屬性是一個信息屬性(可能爲Excel優化)。您仍然需要提供列的寬度。這意味着您必須根據單元格內容實際計算列寬。 Open XML SDK不會自動爲您執行此操作,所以最好爲此使用第三方庫。

+1

它應該是這個BestFit財產更好的解決方案!現在是2014年8月 –

0

這裏可能式 寬度=截斷([{字符數} * {最大數字寬度} + {5像素的邊距}]/{最大數字寬度} * 256)/ 256

10

你必須不幸地計算出你的自我

這就是我所得到的。它適用於我的數據表格,其中包含一些額外的代碼以照顧我設置的一些樣式。它不以任何方式完美,但爲我所需要的而工作。

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; 
    } 
+0

您尚未定義您的「GetSheetData()」方法。 –

+0

等一下,我明白你的意思了,你的意思是編寫你自己的設置所有單元格值的設置,然後繼續設置列寬,我的不好。 –

+2

AutoSize()中的charWidth變量未使用? – Macke

1

我還沒有時間去考慮它,但不是隻留下意見和a link,我想我會分享從別人誰似乎已做了一些這方面的研究評論。

我個人有問題得到the official formulas以適應現實。即短的字符串得到太小的單元格,更長的字符串得到太大的單元格,最重要的是,Excel中顯示的值比插入到DocumentFormat.OpenXml.Spreadsheet.Column的屬性中的值成比例地小。我的快速解決方案是隻有一個最小寬度。

總之,這裏的評論:

我不得不因爲XLSX文件我感興趣的是自動生成的,並應儘快好看,因爲他們開這樣做到底,所以我看着這個稍微進一步,發現在Excel中準確確定列的大小有幾個問題。

  1. 需要用準確的文字大小,這意味着,而不是使用MeasureString你需要使用MeasureCharacterRanges,看到http://groups.google.com/group/microsoft.public.office.developer.com.add_ins/browse_thread/thread/2fc33557feb72ab4/adaddc50480b8cff?lnk=raot

  2. 儘管規範說要加5個像素(1邊境和各爲2側邊距)Excel似乎使用9 - 1的邊界,5爲領先空間和3爲尾隨空間 - 我只通過使用輔助功能應用程序找到了這一點。放大鏡和使用Excel自動調整列

其實我是立足於基本的字體規格我的計算,所以我實際上並不使用任何MeasureCharacterRanges或MeasureString後的像素計數。如果有人希望從字體度量這樣做,則:

Width = Truncate({DesiredWidth} + 9/{MaxDigitWidth})/256

{MaxDigitWidth}是以96 dpi 舍入到的任何的0..9數字的最近的像素的整數{DesiredWidth}是將所有字符寬度加在一起的總和,其中每個字符寬度是96 dpi處字符的寬度,並舍入爲最接近的整數。請注意,每個字符是舍入不是總數