【问题标题】:Set Print Area - OpenXML with Excel设置打印区域 - 使用 Excel 的 OpenXML
【发布时间】:2016-01-29 14:38:42
【问题描述】:

有人知道如何在 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)

【问题讨论】:

  • 试试这个链接,它可能有帮助,也可能没有帮助..确保查看它提供示例的整个页面..msdn.microsoft.com/en-us/library/cc540662(office.12).aspx
  • 感谢您的建议,但实际上发现了,它使用VB自动化设置打印区域。我需要在要复制到新工作簿中的工作表上维护一个打印区域,如果可能的话,我想使用 OpenXml 来完成它,以保持我的应用程序一致。
  • 如果它是使用 vb 自动化完成的,为什么不使用 OleAutomation 更好地称为 Interop 或 Com-Interop,如果您使用 C# 进行编码
  • 我当前的任务涉及删除 Excel 加载项对 Com-Interop 的依赖。我的公司在 Excel 之上使用自定义计算引擎,使用互操作会导致 Excel 触发真正不必要的计算。最终结果是一个简单的工具,它需要很长时间才能完成一个相对简单的任务。通过删除互操作,我可以通过 OpenXml 操作一个 excel 文档,并在对该文档的所有更改结束时进行一次计算,这反过来又大大减少了完成任务的时间。
  • 如果您修改现有的打印区域或为文档中的工作表添加打印区域定义,并且至少已经定义了一个打印区域,则您的代码可以正常工作。这可能是因为在工作簿中创建第一个打印区域定义时添加了一些其他元素。为了使它工作,您应该只使用一个已经定义了一个打印区域的模板。您还可以从方法的参数中删除 localId 和 definedName。

标签: c# .net excel openxml


【解决方案1】:

我发现了一些关于似乎没有使用 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

更新二:

我已更正了打印区域值字符串格式的错误。对困惑感到抱歉。 我还采用了您发布的代码并基于它创建了一个方法。它工作正常,修改打印区域后,我可以毫无问题地在 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();
        }
    }

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

【讨论】:

  • 这看起来很有希望。我会及时通知你..谢谢
  • 关于更新的注意事项:这如何更改或设置 PrintArea?
  • 我想我现在已经找到了它是如何完成的,但是告诉我你需要始终设置相同的打印区域还是动态决定它是什么。
  • 我必须根据模板工作表进行设置。 (即从模板确定打印区域,并为我从模板复制的每个工作表设置 x 次。
  • 谢谢卢卡斯!非常感谢您的帮助!
【解决方案2】:

让我解释一下我的情况:我有带有以下工作表(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 集合中,它就起作用了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 2023-01-19
    相关资源
    最近更新 更多