将幻灯片移至演示文稿中的新位置

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式将幻灯片移动到演示文稿中的新位置。


获取 Presentation 对象

在 Open XML SDK 中 PresentationDocument , 类表示演示文稿文档包。 若要处理演示文稿文档,请先创建 类的 PresentationDocument 实例,然后使用该实例。 若要从文档创建类实例, Open 请调用使用文件路径的方法,并使用布尔值作为第二个参数来指定文档是否可编辑。 若要统计演示文稿中幻灯片的数目,最好打开文件进行只读访问,以避免意外写入文件。 为此,请指定布尔参数的值 false ,如以下 using 语句所示。 在此代码中 presentationFile , 参数是一个字符串,表示要从中打开文档的文件的路径。

{
    // Open the presentation as read-only.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))

在 v3.0.0+ 中, Close() 已删除 方法,转而依赖于 using 语句。 这可确保在 Dispose() 到达右大括号时自动调用 方法。 语句后面的 using 块为在 语句中创建 using 或命名的对象建立作用域,在本例 presentationDocument中为 。


基本演示文稿文档结构

文档的基本文档结构PresentationML由多个部分组成,其中包括包含表示定义的main部分。 ISO/IEC 29500 规范中的以下文本介绍了包的整体PresentationML形式。

包的main部分PresentationML以演示文稿根元素开头。 该元素包含演示文稿,演示文稿又引用幻灯片 列表、幻灯片母版 列表、备注母版 列表和讲义母版 列表。 幻灯片列表指的是演示文稿中的所有幻灯片;幻灯片母版列表指的是演示文稿中使用的全部幻灯片母版;备注母版包含有关备注页格式的信息;讲义母版描述讲义的外观。

讲义 是可提供给访问群体 的一组打印的幻灯片。

除了文本和图形,每个幻灯片还可以包含注释备注,可以具有布局,并且可以是一个或多个自定义演示文稿 的组成部分。 注释是供维护演示文稿幻灯片平台的人员参考的批注。 备注是供演示者或访问群体参考的提醒信息或一段文字。

文档可以包括以下其他功能 PresentationML动画音频视频和幻灯片之间的 切换 效果。

文档 PresentationML 不作为一个大正文存储在单个部件中。 而实现某些功能组合的元素会存储在各个部件中。 例如,文档中的所有作者都存储在一个作者部件中,而每个幻灯片都有自己的部分。

ISO/IEC 29500:2016

以下 XML 代码示例代表包含用 ID 267 和 256 表示的两个幻灯片的演示文稿。

    <p:presentation xmlns:p="…" … > 
       <p:sldMasterIdLst>
          <p:sldMasterId
             xmlns:rel="https://…/relationships" rel:id="rId1"/>
       </p:sldMasterIdLst>
       <p:notesMasterIdLst>
          <p:notesMasterId
             xmlns:rel="https://…/relationships" rel:id="rId4"/>
       </p:notesMasterIdLst>
       <p:handoutMasterIdLst>
          <p:handoutMasterId
             xmlns:rel="https://…/relationships" rel:id="rId5"/>
       </p:handoutMasterIdLst>
       <p:sldIdLst>
          <p:sldId id="267"
             xmlns:rel="https://…/relationships" rel:id="rId2"/>
          <p:sldId id="256"
             xmlns:rel="https://…/relationships" rel:id="rId3"/>
       </p:sldIdLst>
           <p:sldSz cx="9144000" cy="6858000"/>
       <p:notesSz cx="6858000" cy="9144000"/>
    </p:presentation>

使用 Open XML SDK,可以使用对应于 PresentationML 元素的强类型类创建文档结构和内容。 可以在 命名空间中找到 这些类。 下表列出了对应于 、、 sldLayoutsldMasternotesMaster 元素的类的sld类名。

PresentationML 元素 Open XML SDK 类 说明
<sld/> Slide 演示文稿幻灯片。 它是 SlidePart 的根元素。
<sldLayout/> SlideLayout 幻灯片版式。 它是 SlideLayoutPart 的根元素。
<sldMaster/> SlideMaster 幻灯片母版。 它是 SlideMasterPart 的根元素。
<notesMaster/> NotesMaster 备注母版(或讲义母版)。 它是 NotesMasterPart 的根元素。

示例代码的工作方式

若要将演示文稿文件中的特定幻灯片移动到新位置,需要首先知道演示文稿中幻灯片的数目。 因此,本主题中的代码分为两部分。 第一部分统计幻灯片的数目,第二部分将幻灯片移动到新位置。


统计幻灯片的数目

用于计算幻灯片数的示例代码由 方法 CountSlides的两个重载组成。 第一个重载使用参数, string 第二个 PresentationDocument 重载使用参数。 在第一种方法 CountSlides 中,示例代码在 语句中 using 打开演示文稿文档。 然后, PresentationDocument 它将 对象传递给第二 CountSlides 个方法,该方法返回一个整数,表示演示文稿中的幻灯片数。

// Pass the presentation to the next CountSlides method
// and return the slide count.
return CountSlides(presentationDocument);

第二CountSlides种方法中,代码验证传入的对象PresentationDocument是否不是 null,如果不是 ,则从 PresentationDocument 对象获取 PresentationPart 对象。 使用 代码 SlideParts 获取 slideCount 并返回它。

int slidesCount = 0;

// Get the presentation part of document.
PresentationPart? presentationPart = presentationDocument.PresentationPart;

// Get the slide count from the SlideParts.
if (presentationPart is not null)
{
    slidesCount = presentationPart.SlideParts.Count();
}

// Return the slide count to the previous method.
return slidesCount;

将幻灯片从一个位置移动到另一位置

将幻灯片移动到新位置需要通过指定布尔参数的值 true 来打开文件进行读/写访问,如以下 using 语句所示。 用于移动幻灯片的代码由 方法的两个重载 MoveSlide 组成。 第一个重载 MoveSlide 方法采用三个参数:一个表示演示文稿文件名和路径的字符串,两个整数分别表示幻灯片的当前索引位置和要移动幻灯片的索引位置。 它将打开演示文稿文件,获取对象,然后将该对象和两个 PresentationDocument 整数 fromto传递到第二个重载 MoveSlide 方法,该方法执行实际移动。

// Move a slide to a different position in the slide order in the presentation.
public static void MoveSlide(string presentationFile, int from, int to)
{
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        MoveSlide(presentationDocument, from, to);
    }
}

第二个重载 MoveSlide 方法 CountSlides 调用 方法以获取演示文稿中的幻灯片数。 然后,代码会检查从零开始的索引 fromto是否在范围内并且彼此不同。

// Move a slide to a different position in the slide order in the presentation.
static void MoveSlide(PresentationDocument presentationDocument, int from, int to)
{
    if (presentationDocument is null)
    {
        throw new ArgumentNullException("presentationDocument");
    }

    // Call the CountSlides method to get the number of slides in the presentation.
    int slidesCount = CountSlides(presentationDocument);

    // Verify that both from and to positions are within range and different from one another.
    if (from < 0 || from >= slidesCount)
    {
        throw new ArgumentOutOfRangeException("from");
    }

    if (to < 0 || from >= slidesCount || to == from)
    {
        throw new ArgumentOutOfRangeException("to");
    }

PresentationPart声明对象并将其设置为等于传入对象的PresentationDocument表示部分。 对象 PresentationPart 用于创建 Presentation 对象,然后创建一个 SlideIdList 对象,该对象代表演示文稿 Presentation 中的幻灯片列表。 将获取源幻灯片(要移动的幻灯片)的幻灯片 ID,然后确定目标幻灯片(幻灯片顺序中要将源幻灯片移到其后面的幻灯片)的位置。

// Get the presentation part from the presentation document.
PresentationPart? presentationPart = presentationDocument.PresentationPart;

// The slide count is not zero, so the presentation must contain slides.            
Presentation? presentation = presentationPart?.Presentation;

if (presentation is null)
{
    throw new ArgumentNullException(nameof(presentation));
}

SlideIdList? slideIdList = presentation.SlideIdList;

if (slideIdList is null)
{
    throw new ArgumentNullException(nameof(slideIdList));
}

// Get the slide ID of the source slide.
SlideId? sourceSlide = slideIdList.ChildElements[from] as SlideId;

if (sourceSlide is null)
{
    throw new ArgumentNullException(nameof(sourceSlide));
}

SlideId? targetSlide = null;

// Identify the position of the target slide after which to move the source slide.
if (to == 0)
{
    targetSlide = null;
}
else if (from < to)
{
    targetSlide = slideIdList.ChildElements[to] as SlideId;
}
else
{
    targetSlide = slideIdList.ChildElements[to - 1] as SlideId;
}

对象的 Remove 方法 SlideID 用于从当前位置删除源幻灯片,然后使用 InsertAfter 对象的 方法 SlideIdList 将源幻灯片插入目标幻灯片后的索引位置。 最后,保存修改的演示文稿。

// Remove the source slide from its current position.
sourceSlide.Remove();

// Insert the source slide at its new position after the target slide.
slideIdList.InsertAfter(sourceSlide, targetSlide);

示例代码

下面是完整的示例代码,可用于在 C# 和 Visual Basic 中将幻灯片从同一个位置移动到另一个位置。

// Counting the slides in the presentation.
public static int CountSlides(string presentationFile)
{
    // Open the presentation as read-only.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
    {
        // Pass the presentation to the next CountSlides method
        // and return the slide count.
        return CountSlides(presentationDocument);
    }
}

// Count the slides in the presentation.
static int CountSlides(PresentationDocument presentationDocument)
{
    int slidesCount = 0;

    // Get the presentation part of document.
    PresentationPart? presentationPart = presentationDocument.PresentationPart;

    // Get the slide count from the SlideParts.
    if (presentationPart is not null)
    {
        slidesCount = presentationPart.SlideParts.Count();
    }

    // Return the slide count to the previous method.
    return slidesCount;
}

// Move a slide to a different position in the slide order in the presentation.
public static void MoveSlide(string presentationFile, int from, int to)
{
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        MoveSlide(presentationDocument, from, to);
    }
}

// Move a slide to a different position in the slide order in the presentation.
static void MoveSlide(PresentationDocument presentationDocument, int from, int to)
{
    if (presentationDocument is null)
    {
        throw new ArgumentNullException("presentationDocument");
    }

    // Call the CountSlides method to get the number of slides in the presentation.
    int slidesCount = CountSlides(presentationDocument);

    // Verify that both from and to positions are within range and different from one another.
    if (from < 0 || from >= slidesCount)
    {
        throw new ArgumentOutOfRangeException("from");
    }

    if (to < 0 || from >= slidesCount || to == from)
    {
        throw new ArgumentOutOfRangeException("to");
    }

    // Get the presentation part from the presentation document.
    PresentationPart? presentationPart = presentationDocument.PresentationPart;

    // The slide count is not zero, so the presentation must contain slides.            
    Presentation? presentation = presentationPart?.Presentation;

    if (presentation is null)
    {
        throw new ArgumentNullException(nameof(presentation));
    }

    SlideIdList? slideIdList = presentation.SlideIdList;

    if (slideIdList is null)
    {
        throw new ArgumentNullException(nameof(slideIdList));
    }

    // Get the slide ID of the source slide.
    SlideId? sourceSlide = slideIdList.ChildElements[from] as SlideId;

    if (sourceSlide is null)
    {
        throw new ArgumentNullException(nameof(sourceSlide));
    }

    SlideId? targetSlide = null;

    // Identify the position of the target slide after which to move the source slide.
    if (to == 0)
    {
        targetSlide = null;
    }
    else if (from < to)
    {
        targetSlide = slideIdList.ChildElements[to] as SlideId;
    }
    else
    {
        targetSlide = slideIdList.ChildElements[to - 1] as SlideId;
    }
    // Remove the source slide from its current position.
    sourceSlide.Remove();

    // Insert the source slide at its new position after the target slide.
    slideIdList.InsertAfter(sourceSlide, targetSlide);
}

另请参阅