使用 Open XML SDK 2.0 更改 Word 2010 文档的打印方向

Office 可视操作方法

**摘要:**使用 Open XML SDK 2.0 中的强类型类可指定 Word 文档的打印方向,而无需将该文档加载到 Microsoft Word 中。

上次修改时间: 2015年3月9日

适用范围: Excel 2010 | Office 2007 | Office 2010 | Open XML | PowerPoint 2010 | VBA | Word 2010

**发布时间:**2010 年 11 月

**供稿人:**Ken Getz,MCW Technologies, LLC(该链接可能指向英文页面)

概述

利用 Open XML 文件格式,可以指定 Microsoft Word 文档的打印方向。Open XML SDK 2.0 添加了可简化对 Open XML 文件格式的访问的强类型类:SDK 将简化处理打印方向这一任务,因为它使您能够更轻松地与 Open XML 内容中的元素进行交互。此直观操作方法附带的代码示例将介绍如何使用 SDK 来实现此目标。

编码

此直观操作方法附带的示例将包含指定 Word 2007 或 Word 2010 文档的打印方向所需的代码。以下各节描述了该代码。

设置引用

若要使用 Open XML SDK 2.0 中的代码,您必须向您的项目添加一些引用。虽然示例项目已包含这些引用,但您必须在您的代码中显式引用以下程序集:

  • WindowsBase - 可以根据您创建的项目的类型为您设置此引用。

  • DocumentFormat.OpenXml - 该程序集由 Open XML SDK 2.0 安装。

您还应将下面的 using/Imports 语句添加到代码文件的顶部。

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

检查过程

WDSetPrintOrientation 过程接受两个参数:一个指示要修改的文档的名称的参数(字符串)和一个描述新的打印方向的参数 (DocumentFormat.OpenXml.Wordprocessing.PageOrientationValues)。

Public Sub WDSetPrintOrientation(
  ByVal fileName As String, 
  ByVal newOrientation As PageOrientationValues)
public static void WDSetPrintOrientation(
  string fileName, PageOrientationValues newOrientation)

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

若要调用此过程,请传递参数值,如示例代码中所示。在您运行示例代码之前,请确认您提供了一个名为 C:\temp\Orientation.docx 的文档,该文档(用于演示)包含多个部分。

WDSetPrintOrientation(
  "C:\temp\Orientation.docx", PageOrientationValues.Portrait)
WDSetPrintOrientation(
  @"C:\temp\Orientation.docx", PageOrientationValues.Portrait);

访问文档

该代码首先会使用 WordprocessingDocument.Open 方法打开文档,并指示应打开文档以供读写访问(最后的 true 参数)。代码将保留一个 Boolean 变量,以跟踪文档是否已更改(以便在出现此情况时能够保存文档)。代码将检索对主文档部分的引用,然后使用该引用检索文档内容中的所有 SectionProperties 后代的集合 - 稍后,代码将使用该集合依次为每个部分设置方向。

    Using document = WordprocessingDocument.Open(fileName, True)
      Dim documentChanged As Boolean = False

      Dim docPart = document.MainDocumentPart
      Dim sections = docPart.Document.Descendants(
        Of SectionProperties)()
  ' Code removed here…
End Using
using (var document = WordprocessingDocument.Open(fileName, true))
{
  bool documentChanged = false;

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

循环访问各个部分

下一个代码块将循环访问 SectionProperties 元素集合的所有部分。对于每个部分,该代码都将初始化一个用于跟踪部分的页面方向是否已更改的变量(可以在不进行更改的情况下使新方向与初始方向匹配),因此,该代码可以更新页面大小和边距。然后,该代码将检索对 SectionProperties 元素的第一个 PageSize 后代的引用。如果此引用不为 空 ,则该代码将根据需要固定方向。

For Each sectPr As SectionProperties In sections
  Dim pageOrientationChanged As Boolean = False

  Dim pgSz As PageSize = sectPr.Descendants(Of PageSize).FirstOrDefault
  If pgSz IsNot Nothing Then
    ' Code removed here…
  End If
Next
foreach (SectionProperties sectPr in sections)
{
  bool pageOrientationChanged = false;

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

设置部分方向

下一个代码块首先会验证 PageSize 元素的 Orient 属性是否存在。与 Microsoft Word Open XML 元素的许多属性一样,该属性 (Property)/属性 (Attribute) 也可能不存在。在此示例中,使用 Open XML SDK 2.0 检索该属性将返回 null 引用。如果该属性不存在,且新方向为 Portrait,则无需执行任何操作 - 这是默认设置,且无需修改文档。如果 Orient 属性已存在,并且其值与作为参数提供给该方法的新方向值不同,则该代码将设置 Orient 属性的 Value 属性,并将设置 pageOrientationChanged 和 documentChanged 标志。(该代码使用 pageOrientationChanged 标志来确定是否必须更新页面大小和边距。它使用 documentChanged 标志来确定是否必须在最后保存文档)。请注意,如果该代码必须创建 Orient 属性,则它还必须创建要在该属性中作为新的 EnumValue 实例存储的值,并在 EnumValue 构造函数中提供新方向。

If pgSz.Orient Is Nothing Then
  If newOrientation <> PageOrientationValues.Portrait Then
    pageOrientationChanged = True
    documentChanged = True
    pgSz.Orient = New EnumValue(
      Of PageOrientationValues)(newOrientation)
  End If
Else
  If pgSz.Orient.Value <> newOrientation Then
    pgSz.Orient.Value = newOrientation
    pageOrientationChanged = True
    documentChanged = True
  End If
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 Then
  Dim width = pgSz.Width
  Dim height = pgSz.Height
  pgSz.Width = height
  pgSz.Height = width
  ' Code removed here…
End If
if (pageOrientationChanged)
{
  var width = pgSz.Width;
  var height = pgSz.Height;
  pgSz.Width = height;
  pgSz.Height = width;
  // Code removed here…
}

固定页边距

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

Dim pgMar As PageMargin =
  sectPr.Descendants(Of PageMargin).FirstOrDefault()
If pgMar IsNot Nothing Then

  ' 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.

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

  pgMar.Top = CType(left, Int32Value)
  pgMar.Bottom = CType(right, Int32Value)
  pgMar.Left = CType(System.Math.Max(
    0, CType(bottom, Int32Value)), UInt32Value)
  pgMar.Right = CType(System.Math.Max(
    0, CType(top, Int32Value)), UInt32Value)
End If
PageMargin pgMar = sectPr.Descendants<PageMargin>().FirstOrDefault();
if (pgMar != 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.

  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 Then
  docPart.Document.Save()
End If
if (documentChanged)
{
  docPart.Document.Save();
}

示例过程

下面的代码示例包含完整的示例过程。

Public Sub WDSetPrintOrientation(
  ByVal fileName As String, ByVal newOrientation As PageOrientationValues)
  Using document = WordprocessingDocument.Open(fileName, True)
    Dim documentChanged As Boolean = False

    Dim docPart = document.MainDocumentPart
    Dim sections = docPart.Document.Descendants(Of SectionProperties)()

    For Each sectPr As SectionProperties In sections

      Dim pageOrientationChanged As Boolean = False

      Dim pgSz As PageSize = sectPr.Descendants(Of PageSize).FirstOrDefault
      If pgSz IsNot Nothing Then
        ' No Orient property? Create it now. Otherwise, just set its value.
        ' Assume that the default orientation is Portrait.
        If pgSz.Orient Is Nothing Then
          ' Need to create the attribute. You do not need to 
          ' create the Orient property if the property doesn't already
          ' exist and you are setting it to Portrait. That's the default value.
          If newOrientation <> PageOrientationValues.Portrait Then
            pageOrientationChanged = True
            documentChanged = True
            pgSz.Orient = New EnumValue(Of PageOrientationValues)(newOrientation)
          End If
        Else
          ' The Orient property exists, but its value
          ' is different than the new value.
          If pgSz.Orient.Value <> newOrientation Then
            pgSz.Orient.Value = newOrientation
            pageOrientationChanged = True
            documentChanged = True
          End If
        End If

        If pageOrientationChanged Then
          ' Changing the orientation isn't enough. You must also change the page size.
          Dim width = pgSz.Width
          Dim height = pgSz.Height
          pgSz.Width = height
          pgSz.Height = width

          Dim pgMar As PageMargin =
            sectPr.Descendants(Of PageMargin).FirstOrDefault()
          If pgMar IsNot Nothing Then

            ' 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.

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

            pgMar.Top = CType(left, Int32Value)
            pgMar.Bottom = CType(right, Int32Value)
            pgMar.Left = CType(System.Math.Max(
              0, CType(bottom, Int32Value)), UInt32Value)
            pgMar.Right = CType(System.Math.Max(
              0, CType(top, Int32Value)), UInt32Value)
          End If
        End If
      End If
    Next

    If documentChanged Then
      docPart.Document.Save()
    End If
  End Using
End Sub
public static void WDSetPrintOrientation(
  string fileName, PageOrientationValues newOrientation)
{
  using (var document = WordprocessingDocument.Open(fileName, true))
  {
    bool documentChanged = false;

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

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

      PageSize pgSz = sectPr.Descendants<PageSize>().FirstOrDefault();
      if (pgSz != null)
      {
        if (pgSz.Orient == null)
        {
          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)
        {
          var width = pgSz.Width;
          var height = pgSz.Height;
          pgSz.Width = height;
          pgSz.Height = width;

          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();
    }
  }
}
读取

此直观操作方法附带的示例描述了将设置 Word 文档的打印方向的代码。若要使用该示例,必须安装 Open XML SDK 2.0(可通过"浏览"一节中列出的链接获得)。该示例还将使用作为 Open XML SDK 2.0 代码示例集的一部分包含的修改后的代码。"浏览"一节还包括指向完整代码示例集的链接,但您无需下载并安装代码示例即可使用该示例。

示例应用程序仅演示了由 Open XML SDK 2.0 提供的一些可用来修改文档结构的可用属性和方法。有关详细信息,请参阅 Open XML SDK 2.0 Productivity Tool 附带的文档。单击应用程序窗口左下角的"Open XML SDK 文档"选项卡,并搜索要研究的类。尽管该文档当前不包含代码示例,但借助此处所示的示例和文档,您应能成功修改示例应用程序。

观看

观看视频

观看视频(该链接可能指向英文页面) | 时长:00:09:24

单击以获取代码

获取代码(该链接可能指向英文页面)

浏览

关于作者
Ken Getz 是 MCW Technologies 的高级顾问。他是 ASP.NET Developers Jumpstart(《ASP.NET 开发人员入门》,Addison-Wesley,2002)、Access Developer's Handbook(《Access 开发人员手册》,Sybex,2001)和 VBA Developer's Handbook, 2nd Edition(《VBA 开发人员手册第 2 版》,Sybex,2001)的合著者。