设置打印区域 - 使用Excel的OpenXML

时间:2011-12-06 18:40:46

标签: c# .net excel openxml

有人知道如何在Excel中通过OpenXML SDK设置打印区域吗?

我尝试使用以下代码:

public void XLUpdateDefinedName(string fileName, string definedName, string newRange)
{
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
    {
        WorkbookPart wbPart = document.WorkbookPart;

        var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
        DefinedName name = definedNames.Descendants<DefinedName>().Where(m => m.Name == definedName).Single();
        UInt32Value locSheetId = name.LocalSheetId;
        name = null;//.Remove();
        wbPart.Workbook.Save();
        name = new DefinedName() { Name = definedName, LocalSheetId = locSheetId , Text = newRange}
            ;
        wbPart.Workbook.Save();
        //newDefinedName.Text = newRange;
        //definedNames.Append(newDefinedName);

    }
}

更新

我继续收到excel的错误,说明文件中包含以下代码的内容不可读。

   public void XLUpdateDefinedName(string fileName, string definedName, string newRange, string sheet, UInt32Value localId)
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
        {                
            String sheetName = sheet;
            string topLeft = newRange.Split(':').First();
            string bottomRight = newRange.Split(':').Last();
            WorkbookPart wbPart = document.WorkbookPart;

            var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
            var nameCollection = definedNames.Descendants<DefinedName>().Where(m => m.Text.StartsWith(sheetName));
            DefinedName name = nameCollection.Count() > 0 ? nameCollection.First() : null;
            UInt32Value locSheetId;
            if (name != null)
            {
                locSheetId = name.LocalSheetId;
                name.Remove();
                wbPart.Workbook.Save();
            }
            else
            {
                locSheetId = localId;
            }
            name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId};
            name.Text = String.Format("{0}!{1}:{2}", sheetName,topLeft,bottomRight);
            definedNames.Append(name);
            wbPart.Workbook.Save();
        }}

newRange的形式($ A $ 10:$ C $ 15)

2 个答案:

答案 0 :(得分:2)

我找到了一些似乎没有使用Interop的方法的信息。您可以尝试以下方式:

//load the work book
...

myWorkBook.Worksheets.First().PageSetup.PrintAreas.Add("A1:F40");

//save the workbook
//...

看看这是否有帮助。我还没有尝试过,但我要验证它。

<强>更新 第一种方法似乎需要一个额外的库。你可以从这里得到它: http://closedxml.codeplex.com/。我自己没有用过它,所以我无法向你保证它是否正常工作。

纯OpenXML解决方案

我设法通过在记事本编辑器中手动修改xlsx文件内容来更改打印区域。

在C#中你应该尝试使用以下方法(它将打印区域设置为 A1:G19 ):

//first you need to get reference to your workbook, but I assume you already have this
//...
//then you can add an information about desired print area
DefinedNames definedNames = new DefinedNames();
DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
definedNames.Append(printAreaDefName);
//then you should append the created element to your workbook
//...
workbook1.Append(definedNames);

您需要更改的内容是行:printAreaDefName.Text = "Worksheet1!$A$1:$G$19";

您应更改文本值以包含以下格式的信息: [工作表名称]![打印区域的左上角]:[打印区域的右下角] 。它应该将您的打印区域设置为一个矩形,其中包含指定的左上角和右下角。

如果要为不同的工作表指定打印区域,请尝试添加多个DefinedName个对象:

  DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
  printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
  definedNames.Append(printAreaDefName);
  DefinedName printAreaDefName2 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)1U };
  printAreaDefName2.Text = "Worksheet2!$B$1:$H$23";
  definedNames.Append(printAreaDefName2);
  DefinedName printAreaDefName3 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)2U };
  printAreaDefName3.Text = "Worksheet3!$A$1:$J$10";
  definedNames.Append(printAreaDefName3);

我还建议使用 OpenXML SDK 2.0生产力工具。它允许您显示所选OpenXML文件的内容,比较文件,验证文件,甚至显示您要编写的C#代码,以便以编程方式重新创建文件:)。 你可以在这里下载: http://www.microsoft.com/download/en/details.aspx?id=5124

更新II:

我更正了打印区域值字符串格式的错误。对困惑感到抱歉。 我还采用了您发布的代码并基于它创建了一个方法。它工作正常,修改打印区域后,我可以在Excel中打开文件,没有问题。该代码假定已经定义了打印范围,您现在只是更改它,但也可以修改它以添加新的打印范围。 这是代码:

private void OpenXmlFileHandling(String fileName)
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
        {
            //some sample values
            String definedName = "Worksheet3";
            String topLeft = "$A$3";
            String bottomRight = "$D$7";

            WorkbookPart wbPart = document.WorkbookPart;

            var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
            var namesCollection = definedNames.Descendants<DefinedName>().Where(m => m.Text.StartsWith(definedName));
            DefinedName name = namesCollection != null ? namesCollection.First() : null;

            UInt32Value locSheetId;
            //we assume that name is not null, because print range for this worksheet was defined in the source template file
            //if name was null, we should probably just assign to locSheetId a number definedNames.Count() + 1 and not remove the name node
            locSheetId = name.LocalSheetId;
            name.Remove();

            wbPart.Workbook.Save();
            name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId, Text = String.Format("{0}!{1}:{2}", definedName, topLeft, bottomRight) };


            definedNames.Append(name);

            wbPart.Workbook.Save();
        }
    }

我将工作表名称和打印区域范围的值放在方法中,这样您就可以看到它们应该具有哪种值。我希望这会有所帮助。

答案 1 :(得分:1)

让我解释一下我的情况:我有以下表格(T1,I1,M1)的excel工作簿。现在我的要求是基于某些条件T1,I1,M1将多次复制到同一个excel工作簿,例如T2,I2,M2,T3,I3,M3等。对我来说,I2,M2对打印区域没有任何问题,但对于复制的纸张T2,T3 ......有问题。因为它有庞大的数据。 excel列上升到“AG”。所以这就是我在代码中做的事情

将新工作表添加到工作簿

sheets.Append(copiedSheet);

首先获取当前的工作表计数

var count = sheets.Count(); 

获取工作表计数,这将在LocalsheetId中用作printarea设置。

仅对于复制的技术表单,打印区域设置不正确。因此需要正确设置。

DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = Convert.ToUInt32(count) };

请注意defName.Text,格式为'T1'!$ A $ 1:$ AG $ 19

printAreaDefName.Text = "'" + copiedSheet.Name + "'!$A$1:$AG$22";

workbookPart.Workbook.DefinedNames.Append(printAreaDefName); 
workbookPart.Workbook.Save();

我无需在DefinedNames集合中添加新的Definedname。所以我刚刚添加到工作簿的definedNames集合中,并且工作正常。