使用 Open XML SDK 2.0 重新对 PowerPoint 2010 演示文稿中的幻灯片进行排序

Office 可视操作方法

**摘要:**使用 Open XML SDK 2.0 for Microsoft Office 中的强类型类可在提供了旧位置和新位置的情况下重新对 Microsoft PowerPoint 2010 文档中的幻灯片进行排序,而无需将该文档加载到 PowerPoint 中。

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

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

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

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

概述

虽然可利用 Open XML 文件格式重新对 Microsoft PowerPoint 2010 或 PowerPoint 2007 文档中的幻灯片进行排序,但执行此操作需要做一些工作。Open XML SDK 2.0 添加了可简化对 Open XML 文件格式的访问的强类型类 - SDK 将简化重新对幻灯片进行排序这一任务。此直观操作方法附带的代码示例将介绍如何使用 SDK 来实现这个目标。

编码

此直观操作方法附带的示例包含在提供了原始位置和新位置的情况下重新对 PowerPoint 2010 或 PowerPoint 2007 文档中的幻灯片进行排序所需的代码。以下各节详细讨论了该代码。

设置引用

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

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

  • DocumentFormat.OpenXml - 由 Open XML SDK 2.0 安装。

此外,应将以下 using/Imports 语句添加到代码文件的顶部。

Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Presentation
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;

检查过程

PPTReorderSlides 过程接受三个参数,这三个参数分别指示要修改的演示文稿的名称(字符串)、要移动的幻灯片的原始位置和要将幻灯片最终放置到的新位置。此示例过程包含了一些启发方法来确定如何处理特定情况:

  • 若要指明您希望将最后的幻灯片用作原始位置或新位置,请为相应的参数传递一个小于 0 的值。(换言之,为原始位置传递值 -1 会导致此过程将演示文稿中最后的幻灯片移动到新位置。)

  • 如果原始位置的值大于演示文稿中的幻灯片数,则此过程会将一系列幻灯片中最后的幻灯片移动到新位置。

  • 如果新位置的值大于演示文稿中的幻灯片数,则此过程会将选定幻灯片移动到演示文稿中的最终位置。

此过程将返回一个指示其结果的值:

  • 如果原始位置和新位置相同,则此过程将不会执行任何操作并返回 -1。

  • 如果此过程移动幻灯片,则它将返回指定幻灯片的新位置。

此过程声明与以下内容类似:

Public Function PPTReorderSlides(ByVal fileName As String, _
  ByVal originalPosition As Integer, 
  ByVal newPosition As Integer) As Integer
public static int PPTReorderSlides(
  string fileName, int originalPosition, int newPosition)

此过程将修改您指定的演示文稿,并将一张幻灯片从 originalPosition 移动到 newPosition。若要调用此过程,请传递参数值,如示例代码中所示。在您运行示例代码之前,请务必提供一个名为 C:\temp\Sample.pptx 的文档 - 该文档(用于演示)至少包含几张幻灯片。下面的代码将演示如何将幻灯片从位置 0 移动到位置 3。

Console.WriteLine(
  PPTReorderSlides("C:\temp\sample.pptx", 0, 3).ToString())
Console.WriteLine(
  PPTReorderSlides("C:\temp\sample.pptx", 0, 3).ToString());

PPTReorderSlides 函数将返回最后的幻灯片的放置位置,该位置可能与请求的新位置不同,这取决于 newPosition 的值和演示文稿中的幻灯片数。如果此函数未移动幻灯片,则将返回 -1。

设置返回值

此示例过程首先将设置返回值,并确定新位置和原始位置是否相同。如果相同,则代码将立即返回。

' Assume that no slide moves; return -1.
Dim returnValue As Integer = -1

' Moving to and from same position? Get out now.
If newPosition = originalPosition Then
  Return returnValue
End If
// Assume that no slide moves; return -1.
int returnValue = -1;

// Moving to and from same position? Get out now.
if (newPosition == originalPosition)
{
  return returnValue;
}

访问演示文稿

接下来,该代码将使用 PresentationDocument.Open 方法打开文档,并指示应打开此文档以供读/写访问(最后的 True 参数)。该代码将立即检索对演示文稿作者部分的引用,如果该引用为 null,则将引发异常(如果该代码找不到此演示文稿部分,则表示演示文稿出错)。

Using doc As PresentationDocument = 
  PresentationDocument.Open(fileName, True)

  ' Get the presentation part of the document.
  Dim presentationPart As PresentationPart = doc.PresentationPart
  ' No presentation part? Something is wrong with the document.
  If presentationPart Is Nothing Then
    Throw New ArgumentException("fileName")
  End If
  ' Code removed here…
End Using
using (PresentationDocument doc = 
  PresentationDocument.Open(fileName, true))
{
  // Get the presentation part of the document.
  PresentationPart presentationPart = doc.PresentationPart;
  // No presentation part? Something is wrong with the document.
  if (presentationPart == null)
  {
    throw new ArgumentException("fileName");
  }
  // Code removed here…
}

使用位置

若要将幻灯片从其当前位置移动到新位置,此过程必须确认这两个数值参数,并且可以调整它们。该代码首先会检索演示文稿中的幻灯片数,并将相应的值存储到一个变量中。如果幻灯片计数为 0,则无需继续操作,并且此过程将返回。在给定幻灯片计数的情况下,此过程会将该计数减 1 来计算最大位置,然后调用 CalcPositions 过程以根据需要调整原始位置和新位置。CalcPositions 过程将检查负值和位于可用幻灯片范围外的位置。在给定对 originalPosition 和 newPosition 值的引用和最大位置值的情况下,CalcPosition 过程将按需调整这些值。

Private Sub CalcPositions(
  ByRef originalPosition As Integer,
  ByRef newPosition As Integer, ByVal maxPosition As Integer)

  ' Adjust the original and new slide position, as necessary.

  If originalPosition < 0 Then
    ' Ask for the slide in the final position? Get that value now.
    originalPosition = maxPosition
  End If

  If newPosition < 0 Then
    ' Ask for the final position? Get that value now.
    newPosition = maxPosition
  End If

  If originalPosition > maxPosition Then
    originalPosition = maxPosition
  End If
  If newPosition > maxPosition Then
    newPosition = maxPosition
  End If
End Sub
private static void CalcPositions(
  ref int originalPosition, ref int newPosition, int maxPosition)
{
  // Adjust the original and new slide position, as necessary.
  if (originalPosition < 0)
  {
    // Ask for the slide in the final position? Get that value now.
    originalPosition = maxPosition;
  }

  if (newPosition < 0)
  {
    // Ask for the final position? Get that value now.
    newPosition = maxPosition;
  }

  if (originalPosition > maxPosition)
  {
    originalPosition = maxPosition;
  }
  if (newPosition > maxPosition)
  {
    newPosition = maxPosition;
  }
}

PPTReorderSlides 过程包含将设置和调用 CalcPositions 过程的以下代码。

' If you are here, you know that presentationPart exists.
Dim slideCount As Integer = presentationPart.SlideParts.Count()

' No slides? Just return -1 indicating that nothing happened.
If slideCount = 0 Then
  Return returnValue
End If

' There are slides. Calculate real positions.
Dim maxPosition As Integer = slideCount - 1

' Adjust the positions, if necessary.
CalcPositions(originalPosition, newPosition, maxPosition)
// If you are here, you know that presentationPart exists.
int slideCount = presentationPart.SlideParts.Count();

// No slides? Just return -1 indicating that nothing happened.
// Original and new positions the same? Nothing to do.
if (slideCount == 0)
{
  return returnValue;
}
// There are slides. Calculate real positions.
int maxPosition = slideCount - 1;
// Adjust the positions, if necessary.
CalcPositions(ref originalPosition, ref newPosition, maxPosition);

执行重新排序

在该代码调整完原始位置和新位置后,示例代码实际上就可以执行重新排序了。当然,如果旧位置和新位置相同,则不必执行任何操作,并且该代码将返回。

  If newPosition <> originalPosition Then
    ' Code removed here…
  End If
End Using
Return returnValue
  if (newPosition != originalPosition)
  {
    // Code removed here…
  }
}
return returnValue;

另一方面,在给定不同的新值和原始值的情况下,该代码首先会检索对演示文稿内容的引用,然后检索演示文稿中的幻灯片 ID 列表。

Dim presentation As Presentation = presentationPart.Presentation
Dim slideIdList As SlideIdList = presentation.SlideIdList
Presentation presentation = presentationPart.Presentation;
SlideIdList slideIdList = presentation.SlideIdList;

紧接着,该代码将检索源幻灯片和目标幻灯片(目标幻灯片当前在新位置显示)所需的幻灯片 ID。

Dim sourceSlide As SlideId =
  CType(slideIdList.ChildElements(originalPosition), SlideId)
Dim targetSlide As SlideId =
  CType(slideIdList.ChildElements(newPosition), SlideId)
SlideId sourceSlide = 
  (SlideId)(slideIdList.ChildElements[originalPosition]);
SlideId targetSlide = 
  (SlideId)(slideIdList.ChildElements[newPosition]);

下一个步骤有点复杂:此过程必须将原始幻灯片移至其新位置,而该代码无法在幻灯片属于 XML 节点树时移动它。因此,该代码必须先从其 XML 树中删除幻灯片,然后再尝试移动它。

sourceSlide.Remove()
sourceSlide.Remove();

对于自由的浮动幻灯片,该代码可轻松将原始幻灯片置于其新位置。如果新位置大于原始位置,则该代码会将原始幻灯片插到目标幻灯片的后面。如果新位置小于原始位置,则该代码会将原始幻灯片插到目标幻灯片的前面。无论采用何种方式,该代码都会设置返回值并保存演示文稿:

If newPosition > originalPosition Then
  slideIdList.InsertAfter(sourceSlide, targetSlide)
Else
  slideIdList.InsertBefore(sourceSlide, targetSlide)
End If

' Set the return value.
returnValue = newPosition

' Save the modified presentation.
presentation.Save()
if (newPosition > originalPosition)
{
  slideIdList.InsertAfter(sourceSlide, targetSlide);
}
else
{
  slideIdList.InsertBefore(sourceSlide, targetSlide);
}

// Set the return value.
returnValue = newPosition;

// Save the modified presentation.
presentation.Save();

示例过程

下面的代码演示了整个示例过程。

Public Function PPTReorderSlides(ByVal fileName As String, _
  ByVal originalPosition As Integer, 
  ByVal newPosition As Integer) As Integer

  ' Assume that no slide moves; return -1.
  Dim returnValue As Integer = -1

  ' Moving to and from same position? Get out now.
  If newPosition = originalPosition Then
    Return returnValue
  End If

  Using doc As PresentationDocument = 
    PresentationDocument.Open(fileName, True)
    ' Get the presentation part of the document.
    Dim presentationPart As PresentationPart = doc.PresentationPart
    ' No presentation part? Something is wrong with the document.
    If presentationPart Is Nothing Then
      Throw New ArgumentException("fileName")
    End If

    ' If you are here, you know that presentationPart exists.
    Dim slideCount As Integer = presentationPart.SlideParts.Count()
     ' No slides? Just return -1 indicating that nothing happened.
    If slideCount = 0 Then
      Return returnValue
    End If

    ' There are slides. Calculate real positions.
    Dim maxPosition As Integer = slideCount - 1

    ' Adjust the positions, if necessary.
    CalcPositions(originalPosition, newPosition, maxPosition)

    ' The two positions could have ended up being the same 
    ' thing. There is nothing to do, in that case. Otherwise,
    ' do the work.
    If newPosition <> originalPosition Then
      Dim presentation As Presentation = presentationPart.Presentation
      Dim slideIdList As SlideIdList = presentation.SlideIdList

      ' Get the slide ID of the source and target slides.
      Dim sourceSlide As SlideId =
        CType(slideIdList.ChildElements(originalPosition), SlideId)
      Dim targetSlide As SlideId =
        CType(slideIdList.ChildElements(newPosition), SlideId)

      ' Remove the source slide from its parent tree. You cannot
      ' move a slide while it is part of an XML node tree.
      sourceSlide.Remove()

      If newPosition > originalPosition Then
        slideIdList.InsertAfter(sourceSlide, targetSlide)
      Else
        slideIdList.InsertBefore(sourceSlide, targetSlide)
      End If

      ' Set the return value.
      returnValue = newPosition

      ' Save the modified presentation.
      presentation.Save()
    End If
  End Using
  Return returnValue
End Function

Private Sub CalcPositions(
  ByRef originalPosition As Integer,
  ByRef newPosition As Integer, ByVal maxPosition As Integer)

  ' Adjust the original and new slide position, as necessary.

  If originalPosition < 0 Then
    ' Ask for the slide in the final position? Get that value now.
    originalPosition = maxPosition
  End If

  If newPosition < 0 Then
    ' Ask for the final position? Get that value now.
    newPosition = maxPosition
  End If

  If originalPosition > maxPosition Then
    originalPosition = maxPosition
  End If
  If newPosition > maxPosition Then
    newPosition = maxPosition
  End If
End Sub
public static int PPTReorderSlides(string fileName, int originalPosition, int newPosition)
{
  // Assume that no slide moves; return -1.
  int returnValue = -1;

  // Moving to and from same position? Get out now.
  if (newPosition == originalPosition)
  {
    return returnValue;
  }

  using (PresentationDocument doc = 
    PresentationDocument.Open(fileName, true))
  {
    // Get the presentation part of the document.
    PresentationPart presentationPart = doc.PresentationPart;
    // No presentation part? Something is wrong with the document.
    if (presentationPart == null)
    {
      throw new ArgumentException("fileName");
    }

    // If you are here, you know that presentationPart exists.
    int slideCount = presentationPart.SlideParts.Count();

    // No slides? Just return -1 indicating that nothing happened.
    if (slideCount == 0)
    {
      return returnValue;
    }

    // There are slides. Calculate real positions.
    int maxPosition = slideCount - 1;

    // Adjust the positions, if necessary.
    CalcPositions(ref originalPosition, ref newPosition, maxPosition);

    // The two positions could have ended up being the same 
    // thing. There is nothing to do, in that case. Otherwise,
    // do the work.
    if (newPosition != originalPosition)
    {
      Presentation presentation = presentationPart.Presentation;
      SlideIdList slideIdList = presentation.SlideIdList;

      // Get the slide ID of the source and target slides.
      SlideId sourceSlide = 
        (SlideId)(slideIdList.ChildElements[originalPosition]);
      SlideId targetSlide = 
        (SlideId)(slideIdList.ChildElements[newPosition]);

      // Remove the source slide from its parent tree. You cannot
      // move a slide while it is part of an XML node tree.
      sourceSlide.Remove();

      if (newPosition > originalPosition)
      {
        slideIdList.InsertAfter(sourceSlide, targetSlide);
      }
      else
      {
        slideIdList.InsertBefore(sourceSlide, targetSlide);
      }

      // Set the return value.
      returnValue = newPosition;

      // Save the modified presentation.
      presentation.Save();
    }
  }
  return returnValue;
}

private static void CalcPositions(
  ref int originalPosition, ref int newPosition, int maxPosition)
{
  // Adjust the original and new slide position, as necessary.
  if (originalPosition < 0)
  {
    // Ask for the slide in the final position? Get that value now.
    originalPosition = maxPosition;
  }

  if (newPosition < 0)
  {
    // Ask for the final position? Get that value now.
    newPosition = maxPosition;
  }

  if (originalPosition > maxPosition)
  {
    originalPosition = maxPosition;
  }
  if (newPosition > maxPosition)
  {
    newPosition = maxPosition;
  }
}
读取

此直观操作方法附带的示例演示了将重新对 PowerPoint 演示文稿中的幻灯片进行排序的代码。若要使用该示例,必须安装 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:07

单击以获取代码

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

浏览

关于作者
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)的合著者。