更改字处理文档的打印方向

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式设置Microsoft Word 2010或Microsoft Word 2013文档的打印方向。 本文包含一个演示此任务的示例 SetPrintOrientation 方法。


SetPrintOrientation 方法

可以使用 SetPrintOrientation 方法更改字处理文档的打印方向。 方法接受两个参数,这些参数指示要修改 (字符串) 的文档的名称,以及新的打印方向 (PageOrientationValues) 。

以下代码显示 SetPrintOrientation 方法。

    public static void SetPrintOrientation(
      string fileName, PageOrientationValues newOrientation)

对于文档中的每个部分,如果新的方向与该部分当前的打印方向不同,则该代码将修改该部分的打印方向。 此外,该代码必须手动更新每个部分的宽度、高度和边距。


调用示例 SetPrintOrientation 方法

若要调用示例 SetPrintOrientation 方法,请传递包含要转换的文件的名称的字符串。 以下代码显示示例方法调用。

    SetPrintOrientation(@"C:\Users\Public\Documents\ChangePrintOrientation.docx", 
        PageOrientationValues.Landscape);

代码的工作方式

以下代码先使用 Open 方法打开文档,并将 isEditable 参数设置为 true,以指示应读/写该文档。 该代码将保留一个布尔变量来跟踪文档是否已更改(以便在稍后出现此情况时能够保存文档)。 代码检索对 main 文档部件的引用,然后使用该引用检索文档内容中 SectionProperties 类型的所有后代的集合。 稍后,代码将使用此集合轮流为每个部分设置方向。

    using (var document = 
        WordprocessingDocument.Open(fileName, true))
    {
        bool documentChanged = false;

        var docPart = document.MainDocumentPart;
        var sections = docPart.Document.Descendants<SectionProperties>();
        // Code removed here...
    }

循环访问所有部分

下一个代码块将循环访问 SectionProperties 元素集合的所有部分。 对于每个部分,该代码都将初始化一个用于跟踪该部分的页面方向是否已更改的变量,以便代码能够更新页面大小和边距。 (如果新方向与原始方向匹配,则代码不会更新 page。) 代码继续检索对 SectionProperties 元素的第一个 PageSize 后代的引用。 如果此引用不为空,则该代码将根据需要更新方向。

    foreach (SectionProperties sectPr in sections)
    {
        bool pageOrientationChanged = false;

        PageSize pgSz = sectPr.Descendants<PageSize>().FirstOrDefault();
        if (pgSz != null)
        {
            // Code removed here...
        }
    }

设置部分的方向

下一个代码块首先检查 PageSize 元素的 Orient 属性是否存在。 与 Open XML 元素的许多属性一样,属性或特性可能尚不存在。 在这种情况下,检索 属性将返回 null 引用。 默认情况下,如果 属性不存在,并且新方向为 Portrait,则代码不会更新页面。 如果 Orient 属性已存在,并且其值与作为参数提供给该方法的新方向值不同,则该代码将设置 Orient 属性的 Value 属性,并将设置 pageOrientationChangeddocumentChanged 标志。 (代码使用 pageOrientationChanged 标志来确定它是否必须更新页面大小和页边距。它使用 documentChanged 标志来确定它是否必须在 end 保存文档。)

注意

如果代码必须创建 Orient 属性,则它还必须创建要在属性中存储的值,作为新的 EnumValue<T> 实例,在 EnumValue 构造函数中提供新方向。

    if (pgSz.Orient == null)
    {
        if (newOrientation != PageOrientationValues.Portrait)
        {
            pageOrientationChanged = true;
            documentChanged = true;
            pgSz.Orient = 
                new EnumValue<PageOrientationValues>(newOrientation);
        }
    }
    else
    {
        if (pgSz.Orient.Value != newOrientation)
        {
            pgSz.Orient.Value = newOrientation;
            pageOrientationChanged = true;
            documentChanged = true;
        }
    }

更新页面大小

此时,在代码中,页面方向可能已更改。 如果是这样,则代码必须完成另外两个任务。 它必须更新页面大小,并更新分区的页边距。 第一个任务很简单 ,以下代码只需交换页面高度和宽度,将值存储在 PageSize 元素中。

    if (pageOrientationChanged)
    {
        // Changing the orientation is not enough. You must also 
        // change the page size.
        var width = pgSz.Width;
        var height = pgSz.Height;
        pgSz.Width = height;
        pgSz.Height = width;
        // Code removed here...
    }

更新边距

本示例过程中的下一个步骤是处理该部分的边距。 如果页面方向已更改,则该代码必须旋转边距以进行匹配。 为此,该代码将检索对该部分的 PageMargin 元素的引用。 如果该元素存在,该代码将旋转这些边距。 请注意,该代码会将边距旋转 90 度 - 而一些打印机会将边距旋转 270 度,并且您可以修改代码来说明这一点。 另请注意,PageMargin 对象的 TopBottom 属性是有符号值,LeftRight 属性是无符号值。 当该代码旋转边距设置时,它必须在这两类值之间转换,如下面的代码所示。

    PageMargin pgMar = 
        sectPr.Descendants<PageMargin>().FirstOrDefault();
    if (pgMar != null)
    {
        var top = pgMar.Top.Value;
        var bottom = pgMar.Bottom.Value;
        var left = pgMar.Left.Value;
        var right = pgMar.Right.Value;

        pgMar.Top = new Int32Value((int)left);
        pgMar.Bottom = new Int32Value((int)right);
        pgMar.Left = 
            new UInt32Value((uint)System.Math.Max(0, bottom));
        pgMar.Right = 
            new UInt32Value((uint)System.Math.Max(0, top));
    }

保存文档

完成所有修改后,代码将确定文档是否已更改。 如果文档已更改,代码将保存它。

    if (documentChanged)
    {
        docPart.Document.Save();
    }

示例代码

下面是 C# 和 Visual Basic 中的完整 SetPrintOrientation 示例代码。

#nullable enable

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Linq;

SetPrintOrientation(args[0], args[1]);

// Given a document name, set the print orientation for 
// all the sections of the document.
static void SetPrintOrientation(string fileName, string no)
{
    PageOrientationValues newOrientation = no.ToLower() switch
    {
        "landscape" => PageOrientationValues.Landscape,
        "portrait" => PageOrientationValues.Portrait,
        _ => throw new System.ArgumentException("Invalid argument: " + no)
    };

    using (var document =
        WordprocessingDocument.Open(fileName, true))
    {
        bool documentChanged = false;

        if (document.MainDocumentPart is null)
        {
            throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
        }

        var docPart = document.MainDocumentPart;


        var sections = docPart.Document.Descendants<SectionProperties>();

        foreach (SectionProperties sectPr in sections)
        {
            bool pageOrientationChanged = false;

            PageSize pgSz = sectPr.Descendants<PageSize>().First();

            // No Orient property? Create it now. Otherwise, just 
            // set its value. Assume that the default orientation 
            // is Portrait.
            if (pgSz.Orient is null)
            {
                // Need to create the attribute. You do not need to 
                // create the Orient property if the property does not 
                // already exist, and you are setting it to Portrait. 
                // That is the default value.
                if (newOrientation != PageOrientationValues.Portrait)
                {
                    pageOrientationChanged = true;
                    documentChanged = true;
                    pgSz.Orient =
                        new EnumValue<PageOrientationValues>(newOrientation);
                }
            }
            else
            {
                // The Orient property exists, but its value
                // is different than the new value.
                if (pgSz.Orient.Value != newOrientation)
                {
                    pgSz.Orient.Value = newOrientation;
                    pageOrientationChanged = true;
                    documentChanged = true;
                }

                if (pageOrientationChanged)
                {
                    // Changing the orientation is not enough. You must also 
                    // change the page size.
                    var width = pgSz.Width;
                    var height = pgSz.Height;
                    pgSz.Width = height;
                    pgSz.Height = width;

                    PageMargin pgMar = (sectPr.Descendants<PageMargin>().FirstOrDefault()) ?? throw new ArgumentNullException("There are no PageMargin elements in the section.");

                    if (pgMar is not null)
                    {
                        // Rotate margins. Printer settings control how far you 
                        // rotate when switching to landscape mode. Not having those
                        // settings, this code rotates 90 degrees. You could easily
                        // modify this behavior, or make it a parameter for the 
                        // procedure.
                        if (pgMar.Top is null || pgMar.Bottom is null || pgMar.Left is null || pgMar.Right is null)
                        {
                            throw new ArgumentNullException("One or more of the PageMargin elements is null.");
                        }

                        var top = pgMar.Top.Value;
                        var bottom = pgMar.Bottom.Value;
                        var left = pgMar.Left.Value;
                        var right = pgMar.Right.Value;

                        pgMar.Top = new Int32Value((int)left);
                        pgMar.Bottom = new Int32Value((int)right);
                        pgMar.Left =
                            new UInt32Value((uint)System.Math.Max(0, bottom));
                        pgMar.Right =
                            new UInt32Value((uint)System.Math.Max(0, top));
                    }
                }
            }
        }
        if (documentChanged)
        {
            docPart.Document.Save();
        }
    }
}

另请参阅