Creating PowerPoint 2007 Presentations Based on Word Documents by Using Visual Studio 2005 Tools for the Office System SE
Summary: Create a Microsoft Office PowerPoint 2007 presentation based on a Microsoft Office Word 2007 document containing an article or book excerpt.
Applies to: 2007 Microsoft Office System, Microsoft Office PowerPoint 2007, Microsoft Office Word 2007, Microsoft Visual Studio 2005, Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System Second Edition
Ken Getz, MCW Technologies, LLC
October 2007
Code It | Read It | Explore It
Code It
In this example, you create a Microsoft Office Fluent Ribbon customization that adds a button to the Add-Ins tab in Word 2007. Clicking the button creates a new PowerPoint 2007 presentation based on the currently loaded Word 2007 document. To demonstrate the technique, follow these steps.
To create a new button on the Word 2007 Add-Ins tab
In Visual Studio 2005, create a new Visual Studio 2005 Tools for Office Second Edition add-in for Word 2007. Name the new project CreatePresentationAddIn.
In Solution Explorer, right-click the project, and then click Add New Item.
In the Add New Item dialog box, select Ribbon support.
Click Add to insert the new Office Fluent Ribbon customization.
Modify the new Ribbon1.xml file, replacing the existing content with the following XML.
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="OnLoad"> <ribbon> <tabs> <tab idMso="TabAddIns"> <group id="MyGroup" label="Visual How-To"> <button id="button1" size="large" label="Create PPT" screentip="Create presentation based on the current document." onAction="OnClick" imageMso="MicrosoftPowerPoint" /> </group> </tab> </tabs> </ribbon> </customUI>
In Solution Explorer, right-click the CreatePresentationAddIn project, and click Properties.
In the Properties pane, click the Resources tab.
In Solution Explorer, drag the Ribbon1.xml file into the Properties pane to add the Ribbon1.xml file as a project resource.
Close the Properties pane, and click Yes when you are prompted to save.
In the Ribbon1.vb or Ribbon1.cs file, uncomment the ThisAddIn partial class.
In Microsoft Visual C# only, at the top of the code file, add the following using statement.
using Word=Microsoft.Office.Interop.Word;
In the Ribbon1 class, modify the existing GetCustomUI implementation so that it retrieves the Ribbon1 resource.
In Visual C#, expand the IRibbonExtensibility members code region to find the procedure.
Return My.Resources.Ribbon1
return Properties.Resources.Ribbon1;
In the Ribbon1 class, add the following callback procedure. Click the new button on the Office Fluent Ribbon to call this procedure.
Public Sub OnClick(ByVal control As Office.IRibbonControl) End Sub
public void OnClick(Office.IRibbonControl control) { }
Save the project, and run it. In Word 2007, on the Office Fluent Ribbon, click the Add-Ins tab, and verify that the new button appears. Close Word 2007, and return to Visual Studio 2005.
To programmatically interact with the PowerPoint 2007 object model, you must add a reference to the appropriate type library in your project.
To add a reference to the type library
In Solution Explorer, right-click the project, and then click Add Reference.
In the Add Reference dialog box, click the COM tab, and then select the Microsoft PowerPoint 12.0 Object Library reference.
Click OK to add the reference.
Next, you want to store all the code that creates the PowerPoint 2007 presentation.
To store the code that creates the PowerPoint 2007 presentation
Select Project, and then click Add Class.
Name the new class DocToPPT, and click Add to insert the new class.
At the top of the DocToPPT.vb or DocToPPT.cs file, add the following statements.
Imports System.Collections.Generic Imports PowerPoint = Microsoft.Office.Interop.PowerPoint Imports Office = Microsoft.Office.Core
using PowerPoint = Microsoft.Office.Interop.PowerPoint; using Word = Microsoft.Office.Interop.Word; using Office = Microsoft.Office.Core; using System.Windows.Forms;
In the DocToPPT class, add the following private class to maintain information about the various headings within the document.
Private Class HeadingInfo Public Text As String Public Level As Integer Public Index As Integer Public Sub New(ByVal text As String) Me.Text = text End Sub End Class
private class HeadingInfo { public string Text; public int Level; public int Index; public HeadingInfo(string text) { this.Text = text; } }
Add the following declarations to the DocToPPT class to store heading information and to refer to the host Application object.
Private Shared allHeadings As List(Of HeadingInfo) Private Shared level2Headings As List(Of HeadingInfo) Private Shared level1Headings As List(Of HeadingInfo) Private Shared Application As Word.Application = _ Globals.ThisAddIn.Application
private static List<HeadingInfo> allHeadings; private static List<HeadingInfo> level2Headings; private static List<HeadingInfo> level1Headings; private static Word.Application Application = Globals.ThisAddIn.Application
Add the following procedure to the DocToPPT class.
This procedure calls the GetCrossReferenceItems method to retrieve all the headings from the Word document, named c. This hands back an array, stored in a VBA Variant value. The common language runtime treats this as an Object type, and you must cast it as an Array before you can access its contents. The code loops through all the items in the array and determines the heading level for each heading by examining the number of leading spaces on each heading; more spaces indicates a lower level of heading. The code creates several lists of headings that it uses when the PowerPoint 2007 presentation is created.
Private Shared Sub GetHeadings() Dim spaces As New String(" "c, 8) ' Get all the headings in the current document. Dim doc As Word.Document = Application.ActiveDocument Dim headings As Object = _ doc.GetCrossReferenceItems(Word.WdReferenceType.wdRefTypeHeading) ' Convert the variant array into a .NET Array. Dim items As Array = CType(headings, Array) ' Loop through all the items in the array. They are ' numbered using a 1-based index, because ' the array came from VBA. For i As Integer = _ items.GetLowerBound(0) To items.GetUpperBound(0) ' Get the text from the array. Dim itemText As String = items(i).ToString() ' Create the new heading item, trimming the leading ' and trailing spaces. Dim heading As New HeadingInfo(itemText.Trim()) heading.Index = i ' Categorize the headings by level. The code ' recognizes only level 1 and level 2 headings, ' but if you need the other levels, they are here. If String.CompareOrdinal(itemText, 0, spaces, 0, 8) = 0 Then ' Eight leading spaces? It is level 5. heading.Level = 5 ElseIf String.CompareOrdinal(itemText, 0, spaces, 0, 6) = 0 Then ' Six leading spaces? It is level 4. heading.Level = 4 ElseIf String.CompareOrdinal(itemText, 0, spaces, 0, 4) = 0 Then ' Four leading spaces? It is level 3. heading.Level = 3 ElseIf String.CompareOrdinal(itemText, 0, spaces, 0, 2) = 0 Then ' Two leading spaces? It is level 2. heading.Level = 2 level2Headings.Add(heading) Else heading.Level = 1 level1Headings.Add(heading) End If allHeadings.Add(heading) Next i End Sub
private static void GetHeadings() { string spaces = new string(' ', 8); // Get all the headings in the current document. Word.Document doc = Application.ActiveDocument; object crossRefType = Word.WdReferenceType.wdRefTypeHeading; object headings = doc.GetCrossReferenceItems(ref crossRefType); // Convert the variant array into a .NET Array. Array items = ((Array)(headings)); // Loop through all the items in the array. They are // numbered using a 1-based index, because // the array came from VBA. for (int i = items.GetLowerBound(0); i <= items.GetUpperBound(0); i++) { // Get the text from the array. string itemText = items.GetValue(i).ToString(); // Create the new heading item, trimming the leading // and trailing spaces. HeadingInfo heading = new HeadingInfo(itemText.Trim()); heading.Index = i; // Categorize the headings by level. The code // recognizes only level 1 and level 2 headings, // but if you need the other levels, they are here. if (string.CompareOrdinal(itemText, 0, spaces, 0, 8) == 0) { // Eight leading spaces? It is level 5. heading.Level = 5; } else if (string.CompareOrdinal(itemText, 0, spaces, 0, 6) == 0) { // Six leading spaces? It is level 4. heading.Level = 4; } else if (string.CompareOrdinal(itemText, 0, spaces, 0, 4) == 0) { // Four leading spaces? It is level 3. heading.Level = 3; } else if (string.CompareOrdinal(itemText, 0, spaces, 0, 2) == 0) { // Two leading spaces? It is level 2. heading.Level = 2; level2Headings.Add(heading); } else { heading.Level = 1; level1Headings.Add(heading); } allHeadings.Add(heading); } }
The add-in must be able to create a single string that contains all the level 2 headings, separated with a line break. To support this behavior, add the following procedure to the DocToPPT class.
This procedure loops through each item in the list of headings, adds each to an array of strings, and calls the String.Join method to create the output string.
Private Shared Function BuildAgendaList( _ ByVal headings As List(Of HeadingInfo)) As String ' Loop through all the items and ' return an agenda list. ' Create an array of strings. Dim items(headings.Count - 1) As String ' Copy the items into the array of strings. For i As Integer = 0 To headings.Count - 1 items(i) = headings(i).Text Next ' Concatenate the items, with a CR/LF between ' each item. Return String.Join(Environment.NewLine, items) End Function
private static string BuildAgendaList(List<HeadingInfo> headings) { // Loop through all the items and // return an agenda list. // Create an array of strings. string[] items = new string[headings.Count]; // Copy the items into the array of strings. for (int i = 0; i < headings.Count; i++) { items[i] = headings[i].Text; } // Concatenate the items, with a CR/LF between // each item. return string.Join(Environment.NewLine, items); }
In the DocToPPT class, add the following two procedures.
These two overloaded procedures simplify the task of adding a new slide to the presentation. This code lets you specify the presentation, the title, and the layout of the slide. The code then adds a new slide to the end of the presentation, sets its title, and returns a reference to the new slide.
Private Shared Function AddSlide( _ ByVal presentation As PowerPoint.Presentation, _ ByVal title As String) As PowerPoint.Slide Return AddSlide(presentation, title, _ PowerPoint.PpSlideLayout.ppLayoutText) End Function Private Shared Function AddSlide( _ ByVal presentation As PowerPoint.Presentation, _ ByVal title As String, _ ByVal layout As PowerPoint.PpSlideLayout) As PowerPoint.Slide ' Add a new slide at the end of the deck, and set its title. Dim slide As PowerPoint.Slide = presentation.Slides.Add( _ presentation.Slides.Count + 1, layout) slide.Shapes(1).TextFrame.TextRange.Text = title Return slide End Function
private static PowerPoint.Slide AddSlide( PowerPoint.Presentation presentation, string title) { return AddSlide(presentation, title, PowerPoint.PpSlideLayout.ppLayoutText); } private static PowerPoint.Slide AddSlide( PowerPoint.Presentation presentation, string title, PowerPoint.PpSlideLayout layout) { // Add a new slide at the end of the deck, and set its title. PowerPoint.Slide slide = presentation.Slides.Add( presentation.Slides.Count + 1, layout); slide.Shapes[1].TextFrame.TextRange.Text = title; return slide; }
In the DocToPPT class, add the following procedure.
This procedure takes as parameters a reference to a PowerPoint presentation and a list of level 1 headings. The code creates a new title slide at the end of the current presentation, setting its text appropriately.
Private Shared Sub AddTitleSlide( _ ByVal presentation As PowerPoint.Presentation) Dim title As String ' There should be a level 1 heading, but if there is not, ' specify a title for the presentation. If level1Headings.Count > 0 Then title = level1Headings(0).Text Else title = "Presentation Title" End If AddSlide(presentation, title, _ PowerPoint.PpSlideLayout.ppLayoutTitle) End Sub
private static void AddTitleSlide( PowerPoint.Presentation presentation) { String title = String.Empty; // There should be a level 1 heading, but if there is not, // specify a title for the presentation. if (level1Headings.Count > 0) { title = level1Headings[0].Text; } else { title = "Presentation Title"; } AddSlide(presentation, title, PowerPoint.PpSlideLayout.ppLayoutTitle); }
The add-in inserts an Agenda slide between each set of subtopics, delimited with level 2 headings in the document. On each Agenda slide, the add-in highlights the current topic and shades or dims all previous topics. To add this behavior, insert the following procedure into the DocToPPT class.
This procedure adds a new slide to the end of the presentation with the correct title, inserts the agenda text into the second shape on the slide, and highlights the paragraphs appropriately.
Private Shared Sub AddAgendaSlide( _ ByVal presentation As PowerPoint.Presentation, _ ByVal agendaText As String, _ ByVal itemIndex As Integer) Dim slide As PowerPoint.Slide = _ AddSlide(presentation, "Agenda") Dim range As PowerPoint.TextRange = _ slide.Shapes(2).TextFrame.TextRange range.Text = agendaText ' Set all the topics you already covered to ' a shadowed color. Remember that PowerPoint ' numbers its items using a 1-based index. For i As Integer = 1 To itemIndex - 1 range.Paragraphs(i).Font.Color.SchemeColor = _ PowerPoint.PpColorSchemeIndex.ppShadow Next i ' Set up the color and attributes for the current ' agenda item. Dim fnt As PowerPoint.Font = range.Paragraphs(itemIndex).Font fnt.Color.SchemeColor = PowerPoint.PpColorSchemeIndex.ppTitle fnt.Bold = Office.MsoTriState.msoTrue fnt.Underline = Office.MsoTriState.msoTrue End Sub
private static void AddAgendaSlide( PowerPoint.Presentation presentation, string agendaText, int itemIndex) { PowerPoint.Slide slide = AddSlide(presentation, "Agenda"); PowerPoint.TextRange range = slide.Shapes[2].TextFrame.TextRange; range.Text = agendaText; // Set all the topics you already covered to // a shadowed color. Remember that PowerPoint // numbers its items using a 1-based index. for (int i = 1; i < itemIndex; i++) { range.Paragraphs(i, 1).Font.Color.SchemeColor = PowerPoint.PpColorSchemeIndex.ppShadow; } // Set up the color and attributes for the current // agenda item. PowerPoint.Font fnt = range.Paragraphs(itemIndex, 1).Font; fnt.Color.SchemeColor = PowerPoint.PpColorSchemeIndex.ppTitle; fnt.Bold = Office.MsoTriState.msoTrue; fnt.Underline = Office.MsoTriState.msoTrue; }
Between Agenda slides, the add-in must insert one slide for each heading, looping until either it runs out of headings, or until it encounters another level 2 heading. When that happens, another Agenda slide is inserted. To add this behavior, insert the following procedure into the DocToPPT class.
Private Shared Sub AddDetailSlide( _ ByVal presentation As PowerPoint.Presentation, _ ByVal item As Integer) ' The item parameter is a 1-based index, but the ' level2Headings list is a 0-based collection. Dim heading As HeadingInfo = level2Headings(item - 1) AddSlide(presentation, heading.Text) ' Move to the heading after the current one. Dim index As Integer = heading.Index + 1 ' Loop through headings until you hit another level 2 heading. ' For each, add a new slide. While index <= allHeadings.Count AndAlso _ allHeadings(index - 1).Level <> 2 AddSlide(presentation, _ allHeadings(index - 1).Text) index += 1 End While End Sub
private static void AddDetailSlide( PowerPoint.Presentation presentation, int item) { // The item parameter is a 1-based index, but the // level2Headings list is a 0-based collection. HeadingInfo heading = level2Headings[item - 1]; AddSlide(presentation, heading.Text); // Move to the heading after the current one. int index = heading.Index + 1; // Loop through headings until you hit another level 2 heading. // For each, add a new slide. while (index <= allHeadings.Count && allHeadings[index - 1].Level != 2) { AddSlide(presentation, allHeadings[index - 1].Text); index += 1; } }
Finally, add the following procedure to the DocToPPT class.
This procedure is the main entry point for creating the presentation. It sets up all the necessary variables and references, creates a new instance of PowerPoint 2007, loops through all the level 2 headings, and creates Agenda and detail slides. Finally, the code displays the new presentation in an instance of PowerPoint 2007, so you can modify the presentation and save it manually.
Public Shared Sub CreatePresentation() Dim ppt As PowerPoint.Application = Nothing Try allHeadings = New List(Of HeadingInfo) level1Headings = New List(Of HeadingInfo) level2Headings = New List(Of HeadingInfo) GetHeadings() ' The agenda information is fixed. It is a list ' of all the level 2 headings, as a series ' of paragraphs (one heading per paragraph). Dim agendaText As String = BuildAgendaList(level2Headings) ' Create a new instance of PowerPoint, ' and create a new presentation. ppt = New PowerPoint.Application Dim presentation As PowerPoint.Presentation = _ ppt.Presentations.Add(Office.MsoTriState.msoTrue) ' Add the title slide. AddTitleSlide(presentation) ' Add agenda slides, and then add the slides between agenda slides, ' until you handle all the slides. There is ' one agenda topic for each level 2 heading, and ' the code inserts a copy of the Agenda slide for ' each level 2 heading, highlighting the current topic. For i As Integer = 1 To level2Headings.Count AddAgendaSlide(presentation, agendaText, i) ' Add the rest of the slides for this agenda item. AddDetailSlide(presentation, i) Next i Catch ex As Exception MessageBox.Show(ex.Message) Finally ' Show the PowerPoint main window. If ppt IsNot Nothing Then ppt.Visible = Office.MsoTriState.msoTrue ppt.Activate() ppt = Nothing End If End Try End Sub
public static void CreatePresentation() { PowerPoint.Application ppt = null; try { allHeadings = new List<HeadingInfo>(); level1Headings = new List<HeadingInfo>(); level2Headings = new List<HeadingInfo>(); GetHeadings(); // The agenda information is fixed. It is a list // of all the level 2 headings, as a series // of paragraphs (one heading per paragraph). string agendaText = BuildAgendaList(level2Headings); // Create a new instance of PowerPoint, // and create a new presentation. ppt = new PowerPoint.Application(); PowerPoint.Presentation presentation = ppt.Presentations.Add(Office.MsoTriState.msoTrue); // Add the title slide. AddTitleSlide(presentation); // Add agenda slides, and add the slides between agenda slides, // until you handle all the slides. There is // one agenda topic for each level 2 heading, and // the code inserts a copy of the Agenda slide for // each level 2 heading, highlighting the current topic. for (int i = 1; i <= level2Headings.Count; i++) { AddAgendaSlide(presentation, agendaText, i); // Add the rest of the slides for this agenda item. AddDetailSlide(presentation, i); } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { // Show the PowerPoint main window. if (ppt != null) { ppt.Visible = Office.MsoTriState.msoTrue; ppt.Activate(); ppt = null; } } }
To complete the add-in, in the Ribbon1 class, modify the OnClick event handler that you created earlier. Add the following code to the procedure, which calls the CreatePresentation method.
DocToPPT.CreatePresentation()
DocToPPT.CreatePresentation();
Save the project.
Load a document that contains a combination of styles, including Heading 1 and Heading 2. Click the Add-Ins tab, and then click the new Create PPT button that the add-in placed in the Visual How-To group on the Office Fluent Ribbon. This action creates a new PowerPoint 2007 presentation based on the headings in the current Word 2007 document. Try modifying the theme. The colors on the Agenda slides update to match the current theme.
Read It
Creating this add-in introduces several issues in dealing with the PowerPoint 2007 object model. This Office Visual How-to article describes the following tasks.
Creating a new PowerPoint 2007 presentation from a Word 2007 document.
Retrieving the headings from a Word 2007 document.
Adding a new slide to a presentation and specifying the layout for the slide.
Adding an "Agenda" slide between each set of level 2 headings.
Modifying the style of text, including using theme colors.
As you might imagine, the PowerPoint 2007 object model is far richer than this one simple add-in can demonstrate. To interact with the PowerPoint object model in code, investigate the documentation in Explore It.