如何:将主题应用于演示文稿

上次修改时间: 2010年10月14日

适用范围: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

本文内容
获取 PresentationDocument 对象
基本演示文稿文档结构
主题元素的结构
示例代码的工作方式
示例代码

本主题演示如何使用 Open XML SDK 2.0 for Microsoft Office 中的类以编程方式将一个演示文稿中的主题应用于另一个演示文稿。

编译本主题中的代码需要使用以下程序集指令。

using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml.Presentation;
using DocumentFormat.OpenXml.Packaging;
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports DocumentFormat.OpenXml.Presentation
Imports DocumentFormat.OpenXml.Packaging

获取 PresentationDocument 对象

在 Open XML SDK 中,PresentationDocument 类表示演示文稿文档包。若要处理演示文稿文档,请首先创建 PresentationDocument 类的实例,然后使用该实例。若要从文档中创建类实例,请调用使用文件路径的 Open(String, Boolean) 方法,并以布尔值作为第二个参数来指定文档是否可编辑。若要打开文档进行只读访问,请为此参数指定值 false。若要打开文档进行读/写访问,请为此参数指定值 true。在下面的 using 语句中,打开两个演示文稿文件,即要应用主题的目标演示文稿和已应用该主题的源演示文稿。打开源演示文稿文件进行只读访问,打开目标演示文稿文件进行读/写访问。在该代码中,themePresentation 参数是表示源演示文稿文档路径的字符串,presentationFile 参数是表示目标演示文稿文档路径的字符串。

using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{
    // Insert other code here.
}
Using themeDocument As PresentationDocument = PresentationDocument.Open(themePresentation, False)
Using presentationDocument As PresentationDocument = PresentationDocument.Open(presentationFile, True)
    ' Insert other code here.
End Using
End Using

using 语句提供典型 .Open, .Save, .Close 序列的建议备选序列。它确保在遇到右大括号时会自动调用 Dispose 方法(Open XML SDK 用来清理资源的内部方法)。using 语句后面的块为 using 语句中创建或指定的对象设定范围,在此示例中这个范围就是 themeDocument 和 presentationDocument。

基本演示文稿文档结构

PresentationML 文档的基本文档结构由包含演示文稿定义的主部件组成。ISO/IEC 29500(该链接可能指向英文页面) 规范中的以下文本介绍了 PresentationML 包的整体形式。

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

讲义是打印的一组幻灯片,可提供给目标群体以供他们将来参考。

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

PresentationML 文档可以包含的其他功能如下:动画、音频、视频以及幻灯片之间的切换。

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

© ISO/IEC29500: 2008。

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

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

通过使用 Open XML SDK 2.0,您可以利用 PresentationML 元素所对应的强类型类创建文档结构和内容。可以在 DocumentFormat.OpenXml.Presentation 命名空间中找到这些类。下表列出了 sld、sldLayout、sldMaster 和 notesMaster 元素所对应类的类名称。

PresentationML 元素

Open XML SDK 2.0 类

说明

sld

Slide

演示文稿幻灯片。它是 SlidePart 的根元素。

sldLayout

SlideLayout

幻灯片版式。它是 SlideLayoutPart 的根元素。

sldMaster

SlideMaster

幻灯片母版。它是 SlideMasterPart 的根元素。

notesMaster

NotesMaster

备注母版(或讲义母版)。它是 NotesMasterPart 的根元素。

主题元素的结构

ISO/IEC 29500(该链接可能指向英文页面) 规范中的以下信息在处理此元素时会很有用。

此元素定义与共享样式表(或主题)关联的根级别复杂类型。此元素保留通过主题提供给文档的所有不同的格式选项并定义在文档中使用主题对象时文档的总体外观。[示例:请考虑以下图像示例中应用于演示文稿的不同主题。在此示例中,可以查看主题如何影响演示文稿中不同对象的字体、颜色、背景、填充和效果。示例结束]

主题示例

在此示例中,我们查看主题如何影响演示文稿中不同对象的字体、颜色、背景、填充和效果。示例结束]

© ISO/IEC29500: 2008。

下表列出 Theme 类可能的子类型。

PresentationML 元素

Open XML SDK 2.0 类

说明

custClrLst

CustomColorList

自定义颜色列表

extLst

ExtensionList

扩展名列表

extraClrSchemeLst

ExtraColorSchemeList

额外配色方案列表

objectDefaults

ObjectDefaults

对象默认值

themeElements

ThemeElements

主题元素

下面的 XML 架构段定义主题元素的四个部件。themeElements 元素是保留主题中定义的主要格式的部件。其他部件提供 themeElements 中所包含信息的重载、默认值和附加内容。定义主题 CT_OfficeStyleSheet 的复杂类型通过以下方式定义。

<complexType name="CT_OfficeStyleSheet">
   <sequence>
       <element name="themeElements" type="CT_BaseStyles" minOccurs="1" maxOccurs="1"/>
       <element name="objectDefaults" type="CT_ObjectStyleDefaults" minOccurs="0" maxOccurs="1"/>
       <element name="extraClrSchemeLst" type="CT_ColorSchemeList" minOccurs="0" maxOccurs="1"/>
       <element name="custClrLst" type="CT_CustomColorList" minOccurs="0" maxOccurs="1"/>
       <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
   </sequence>
   <attribute name="name" type="xsd:string" use="optional" default=""/>
</complexType>

此复杂类型还保留一个 CT_OfficeArtExtensionList,它用于将来对此复杂类型进行扩展。

示例代码的工作方式

该示例代码包含 ApplyThemeToPresentation 方法和 GetSlideLayoutType 方法的两个重载。以下代码段显示第一个重载方法,其中打开两个演示文稿文件 themePresentation 和 presentationFile 并将其作为参数传递给第二个重载方法。

// Apply a new theme to the presentation. 
public static void ApplyThemeToPresentation(string presentationFile, string themePresentation)
{
    using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        ApplyThemeToPresentation(presentationDocument, themeDocument);
    }
}
' Apply a new theme to the presentation. 
Public Shared Sub ApplyThemeToPresentation(ByVal presentationFile As String, ByVal themePresentation As String)
    Using themeDocument As PresentationDocument = PresentationDocument.Open(themePresentation, False)
    Using presentationDocument As PresentationDocument = PresentationDocument.Open(presentationFile, True)
        ApplyThemeToPresentation(presentationDocument, themeDocument)
    End Using
    End Using
End Sub

在第二个重载方法中,代码首先检查是否有任何演示文稿文件为空,如果为空,则引发异常。然后,代码通过声明 PresentationPart 对象并将其设置为等于传入的目标 PresentationDocument 对象的演示文稿部件来获取演示文稿文档的演示文稿部件。接下来,代码从传入的两个对象的演示文稿部件中获取幻灯片母版部件,并获取目标演示文稿的幻灯片母版部件的关系 ID。

// Apply a new theme to the presentation. 
public static void ApplyThemeToPresentation(PresentationDocument presentationDocument, PresentationDocument themeDocument)
{
    if (presentationDocument == null)
    {
        throw new ArgumentNullException("presentationDocument");
    }
    if (themeDocument == null)
    {
        throw new ArgumentNullException("themeDocument");
    }

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

    // Get the existing slide master part.
    SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.ElementAt(0);
    string relationshipId = presentationPart.GetIdOfPart(slideMasterPart);

    // Get the new slide master part.
    SlideMasterPart newSlideMasterPart = themeDocument.PresentationPart.SlideMasterParts.ElementAt(0);
Apply a new theme to the presentation. 
Public Shared Sub ApplyThemeToPresentation(ByVal presentationDocument As PresentationDocument, ByVal themeDocument As PresentationDocument)
    If presentationDocument Is Nothing Then
        Throw New ArgumentNullException("presentationDocument")
    End If
    If themeDocument Is Nothing Then
        Throw New ArgumentNullException("themeDocument")
    End If

    ' Get the presentation part of the presentation document.
    Dim presentationPart As PresentationPart = presentationDocument.PresentationPart

    ' Get the existing slide master part.
    Dim slideMasterPart As SlideMasterPart = presentationPart.SlideMasterParts.ElementAt(0)
    Dim relationshipId As String = presentationPart.GetIdOfPart(slideMasterPart)

    ' Get the new slide master part.
    Dim newSlideMasterPart As SlideMasterPart = themeDocument.PresentationPart.SlideMasterParts.ElementAt(0)

然后,该代码从目标演示文稿中移除现有主题部件和幻灯片母版部件。通过重用旧的关系 ID,代码将新幻灯片母版部件从源演示文稿添加到目标演示文稿中。它还向目标演示文稿中添加主题部件。

// Remove the existing theme part.
presentationPart.DeletePart(presentationPart.ThemePart);

// Remove the old slide master part.
presentationPart.DeletePart(slideMasterPart);

// Import the new slide master part, and reuse the old relationship ID.
newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId);

// Change to the new theme part.
presentationPart.AddPart(newSlideMasterPart.ThemePart);
' Remove the existing theme part.
presentationPart.DeletePart(presentationPart.ThemePart)

' Remove the old slide master part.
presentationPart.DeletePart(slideMasterPart)

' Import the new slide master part, and reuse the old relationship ID.
newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId)

' Change to the new theme part.
presentationPart.AddPart(newSlideMasterPart.ThemePart)

该代码循环访问幻灯片母版部件中的所有幻灯片版式部件并将其添加到新幻灯片版式的列表中。它指定默认布局类型。对于此示例,默认布局类型的代码为"标题和内容"。

Dictionary<string, SlideLayoutPart> newSlideLayouts = new Dictionary<string, SlideLayoutPart>();

foreach (var slideLayoutPart in newSlideMasterPart.SlideLayoutParts)
{
    newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart);
}

string layoutType = null;
SlideLayoutPart newLayoutPart = null;

// Insert the code for the layout for this example.
string defaultLayoutType = "Title and Content";
Dim newSlideLayouts As New Dictionary(Of String, SlideLayoutPart)()

For Each slideLayoutPart In newSlideMasterPart.SlideLayoutParts
    newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart)
Next slideLayoutPart

Dim layoutType As String = Nothing
Dim newLayoutPart As SlideLayoutPart = Nothing

' Insert the code for the layout for this example.
Dim defaultLayoutType As String = "Title and Content"

代码循环访问目标演示文稿中的所有幻灯片部件并移除所有幻灯片中的幻灯片版式关系。它使用 GetSlideLayoutType 方法查找幻灯片版式部件的布局类型。对于具有现有幻灯片版式部件的任何幻灯片,代码会添加幻灯片之前具有的相同类型的新幻灯片版式部件。对于没有现有幻灯片版式部件的任何幻灯片,代码会添加默认类型的新幻灯片版式部件。

// Remove the slide layout relationship on all slides. 
foreach (var slidePart in presentationPart.SlideParts)
{
    layoutType = null;

    if (slidePart.SlideLayoutPart != null)
    {
        // Determine the slide layout type for each slide.
        layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);

        // Delete the old layout part.
        slidePart.DeletePart(slidePart.SlideLayoutPart);
    }

    if (layoutType != null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))
    {
        // Apply the new layout part.
        slidePart.AddPart(newLayoutPart);
    }
    else
    {
        newLayoutPart = newSlideLayouts[defaultLayoutType];

        // Apply the new default layout part.
        slidePart.AddPart(newLayoutPart);
    }
}
' Remove the slide layout relationship on all slides. 
For Each slidePart In presentationPart.SlideParts
    layoutType = Nothing

    If slidePart.SlideLayoutPart IsNot Nothing Then
        ' Determine the slide layout type for each slide.
        layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart)

        ' Delete the old layout part.
        slidePart.DeletePart(slidePart.SlideLayoutPart)
    End If

    If layoutType IsNot Nothing AndAlso newSlideLayouts.TryGetValue(layoutType, newLayoutPart) Then
        ' Apply the new layout part.
        slidePart.AddPart(newLayoutPart)
    Else
        newLayoutPart = newSlideLayouts(defaultLayoutType)

        ' Apply the new default layout part.
        slidePart.AddPart(newLayoutPart)
    End If
Next slidePart

为了获取幻灯片版式类型,代码使用 GetSlideLayoutType 方法,该方法采用幻灯片版式部件作为参数,并向第二个重载的 ApplyThemeToPresentation 方法返回一个表示幻灯片版式类型名称的字符串。

// Get the slide layout type.
public static string GetSlideLayoutType(SlideLayoutPart slideLayoutPart)
{
    CommonSlideData slideData = slideLayoutPart.SlideLayout.CommonSlideData;

    // Remarks: If this is used in production code, check for a null reference.

    return slideData.Name;}
' Get the slide layout type.
Public Shared Function GetSlideLayoutType(ByVal slideLayoutPart As SlideLayoutPart) As String
    Dim slideData As CommonSlideData = slideLayoutPart.SlideLayout.CommonSlideData

    ' Remarks: If this is used in production code, check for a null reference.

    Return slideData.Name
End Function

示例代码

以下是从一个演示文稿向另一个演示文稿复制主题的完整示例代码。若要使用此程序,必须创建两个演示文稿,一个是具有要复制的主题的源演示文稿,如 Myppt9-theme.pptx,另一个是目标演示文稿,如 Myppt9.pptx。在您的程序中可以使用以下调用来执行复制。

string presentationFile=@"C:\Users\Public\Documents\myppt2.pptx";
string themePresentation = @"C:\Users\Public\Documents\myppt2-theme.pptx";
ApplyThemeToPresentation(presentationFile, themePresentation);
Dim presentationFile As String = "C:\Users\Public\Documents\myppt2.pptx"
Dim themePresentation As String = "C:\Users\Public\Documents\myppt2-theme.pptx"
ApplyThemeToPresentation(presentationFile, themePresentation)

在执行该调用后,您可以检查文件 Myppt2.pptx,您将看到文件 Myppt9-theme.pptx 具有相同主题。

// Apply a new theme to the presentation. 
public static void ApplyThemeToPresentation(string presentationFile, string themePresentation)
{
    using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        ApplyThemeToPresentation(presentationDocument, themeDocument);
    }
}

// Apply a new theme to the presentation. 
public static void ApplyThemeToPresentation(PresentationDocument presentationDocument, PresentationDocument themeDocument)
{
    if (presentationDocument == null)
    {
        throw new ArgumentNullException("presentationDocument");
    }
    if (themeDocument == null)
    {
        throw new ArgumentNullException("themeDocument");
    }

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

    // Get the existing slide master part.
    SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.ElementAt(0);
    string relationshipId = presentationPart.GetIdOfPart(slideMasterPart);

    // Get the new slide master part.
    SlideMasterPart newSlideMasterPart = themeDocument.PresentationPart.SlideMasterParts.ElementAt(0);

    // Remove the existing theme part.
    presentationPart.DeletePart(presentationPart.ThemePart);

    // Remove the old slide master part.
    presentationPart.DeletePart(slideMasterPart);

    // Import the new slide master part, and reuse the old relationship ID.
    newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId);

    // Change to the new theme part.
    presentationPart.AddPart(newSlideMasterPart.ThemePart);

    Dictionary<string, SlideLayoutPart> newSlideLayouts = new Dictionary<string, SlideLayoutPart>();

    foreach (var slideLayoutPart in newSlideMasterPart.SlideLayoutParts)
    {
        newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart);
    }

    string layoutType = null;
    SlideLayoutPart newLayoutPart = null;

    // Insert the code for the layout for this example.
    string defaultLayoutType = "Title and Content";

    // Remove the slide layout relationship on all slides. 
    foreach (var slidePart in presentationPart.SlideParts)
    {
        layoutType = null;

        if (slidePart.SlideLayoutPart != null)
        {
            // Determine the slide layout type for each slide.
            layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);

            // Delete the old layout part.
            slidePart.DeletePart(slidePart.SlideLayoutPart);
        }

        if (layoutType != null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))
        {
            // Apply the new layout part.
            slidePart.AddPart(newLayoutPart);
        }
        else
        {
            newLayoutPart = newSlideLayouts[defaultLayoutType];

            // Apply the new default layout part.
            slidePart.AddPart(newLayoutPart);
        }
    }
}

// Get the slide layout type.
public static string GetSlideLayoutType(SlideLayoutPart slideLayoutPart)
{
    CommonSlideData slideData = slideLayoutPart.SlideLayout.CommonSlideData;

    // Remarks: If this is used in production code, check for a null reference.

    return slideData.Name;
}
' Apply a new theme to the presentation. 
Public Sub ApplyThemeToPresentation(ByVal presentationFile As String, ByVal themePresentation As String)
    Dim themeDocument As PresentationDocument = PresentationDocument.Open(themePresentation, False)
    Dim presentationDoc As PresentationDocument = PresentationDocument.Open(presentationFile, True)
    Using (themeDocument)
        Using (presentationDoc)
            ApplyThemeToPresentation(presentationDoc, themeDocument)
        End Using
    End Using

End Sub
' Apply a new theme to the presentation. 
Public Sub ApplyThemeToPresentation(ByVal presentationDocument As PresentationDocument, ByVal themeDocument As PresentationDocument)
    If (presentationDocument Is Nothing) Then
        Throw New ArgumentNullException("presentationDocument")
    End If
    If (themeDocument Is Nothing) Then
        Throw New ArgumentNullException("themeDocument")
    End If

    ' Get the presentation part of the presentation document.
    Dim presentationPart As PresentationPart = presentationDocument.PresentationPart

    ' Get the existing slide master part.
    Dim slideMasterPart As SlideMasterPart = presentationPart.SlideMasterParts.ElementAt(0)

    Dim relationshipId As String = presentationPart.GetIdOfPart(slideMasterPart)

    ' Get the new slide master part.
    Dim newSlideMasterPart As SlideMasterPart = themeDocument.PresentationPart.SlideMasterParts.ElementAt(0)

    ' Remove the theme part.
    presentationPart.DeletePart(presentationPart.ThemePart)

    ' Remove the old slide master part.
    presentationPart.DeletePart(slideMasterPart)

    ' Import the new slide master part, and reuse the old relationship ID.
    newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId)

    ' Change to the new theme part.
    presentationPart.AddPart(newSlideMasterPart.ThemePart)
    Dim newSlideLayouts As Dictionary(Of String, SlideLayoutPart) = New Dictionary(Of String, SlideLayoutPart)()
    For Each slideLayoutPart As Object In newSlideMasterPart.SlideLayoutParts
        newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart)
    Next
    Dim layoutType As String = Nothing
    Dim newLayoutPart As SlideLayoutPart = Nothing

    ' Insert the code for the layout for this example.
    Dim defaultLayoutType As String = "Title and Content"

    ' Remove the slide layout relationship on all slides. 
    For Each slidePart As Object In presentationPart.SlideParts
        layoutType = Nothing
        If (Not (slidePart.SlideLayoutPart) Is Nothing) Then

            ' Determine the slide layout type for each slide.
            layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart)

            ' Delete the old layout part.
            slidePart.DeletePart(slidePart.SlideLayoutPart)
        End If

        If ((Not (layoutType) Is Nothing) AndAlso newSlideLayouts.TryGetValue(layoutType, newLayoutPart)) Then

            ' Apply the new layout part.
            slidePart.AddPart(newLayoutPart)
        Else
            newLayoutPart = newSlideLayouts(defaultLayoutType)

            ' Apply the new default layout part.
            slidePart.AddPart(newLayoutPart)
        End If
    Next
End Sub
' Get the type of the slide layout.
Public Function GetSlideLayoutType(ByVal slideLayoutPart As SlideLayoutPart) As String
    Dim slideData As CommonSlideData = slideLayoutPart.SlideLayout.CommonSlideData

    ' Remarks: If this is used in production code, check for a null reference.
    Return slideData.Name
End Function

请参阅

引用

Class Library Reference