PowerPoint Presentation from SharePoint Content via VSTO

In this article, we will create a PowerPoint Presentation using content of the lists from a SharePoint site.

Windows SharePoint Services (WSS) provides an easy way to create workspaces where information can be collected to share information among users working toward a common goal. This goal may be of different types, including making presentations for an event, execution of a business process, or even materials for a project. Always, organizations build presentations as an output of this collaboration or as a part of regular reporting on the status of the team. Microsoft PowerPoint provides users with a powerful platform to make presentations. However, the presentation creator expend to much effort and time to locate, duplicate and organize this information into the presentation. The presentation's authors are likely retyping, cutting, and pasting or otherwise manually importing content. But this way is somehow error prone and time consuming. So, in this article we not only look for reducing the effort; we also look for increase of accuracy. This article details how we can extend PowerPoint to provide a tool that has capability of building slides populated with content stored in a SharePoint site.

To understand the how this will be useful, let's take an example. Almost any time there is a chain of command in any organization; people farther down are always summarizing and reporting up. For example, in the Software Development firm, there is a project which is of long term work and needs every week a meeting of the work and presentation of the work by PowerPoint slide show. So, they prepare a SharePoint Meeting workspace for their need to be fulfilled and keep their agendas for meeting, the members of the meeting and much other information. Every week, the presentation creators get their agenda information from the site and create presentation in PowerPoint. He does his work by copying and pasting and sometime manually importing content. Also there are so many types of examples are there in the commercial world. So, in this article we will see how to reduce this type of work by providing some handy tool to PowerPoint which will fetch the SharePoint meeting agendas to the PowerPoint and create the slides.

Example Overview

For this type of solution, we will extend Microsoft PowerPoint to provide a tool for the author to import data from a SharePoint site. We have focused our efforts to build a briefing presentation made of the items which are imported from a typical meeting workspace in WSS. Once the tool has been launched, it will examine a site provided by user to see if it contains an objectives list, a list of agenda items, or any slide libraries. The objectives list and agenda lists are default list templates for meeting workspace in SharePoint. In this example, we also have included slide library because users who are a part of this collaboration may have built slides of their own that may be included in our briefing output presentation. Once the site has been crawled, the custom import tool will give a wizard process that offers the user to build slides for the content it finds in the site.

This application is flexible enough so that the presentation author can build slide in any presentation he is working on. To fulfil this requirement, the solution will be an application-level add-in. As an add-in this tool will always be available to the authoring user from within PowerPoint. The controls for this tool will be added to the Microsoft Office ribbon interface as the launching point of the tool. From the ribbon, the author will be able to launch the tool, which presents itself as a custom task pane. This pane provides the user with the wizard experience of steps and prompts, building slides as per current presentation instructions.

As the wizard runs, it asks the user about if he wants to have a presentation slide built for the content it finds in the site. If the user goes for it, the add-in will query the SharePoint site for the objective list items and place them in a new slide as a bulleted list. Same way, if the user selects to build slide from the agenda, the add-in will query the SharePoint site for the agenda list items and place them in a new slide displayed within a table. Also, the add-in will populate the notes page of the slide with details such as owner of the agenda item and notes that are contained in the SharePoint site. At the last step, the add-in will display a list of slide libraries it finds on the site as the links. Each link will open the library in the browser so that the user can select slides to import into the presentation he is working.

Walking through the example development

In the following section we will details the main elements of the solution. The walkthrough will guide you how to get started with Visual Studio to create the briefing PowerPoint add-in. We will also see how we can extend the Office ribbon interface using VSTO. The wizard process will also be explained so you can see how it is implement. Also, the walkthrough will explain the work that goes into building each of the PowerPoint slides for our briefing. This includes creating new slides, putting content as a bulleted list, inserting and populating a table, placing content on a slide’s notes page and linking the SharePoint slide libraries.

Creating the Project

Using Visual Studio to build a PowerPoint add-in project is very easy by using VSTO’s project types. Simply open Visual Studio 2008 and select to create new project. Under the Visual C# language node, expand the Office node and select 2007. This will display Office 2007 VSTO project templates. Select PowerPoint 2007 Add-in. Name the project and solution BriefingCS. Note that the dropdown list of framework selection has the value .NET Framework 3.5.

Once the project is created, you should see few files which are already created by the project template in the Solution Explorer. The PowerPoint node, that when expanded, will have a code file named ThisAddIn.cs. This file is the main entry point for our add-in. In this file a developer can write code for events at the add-in scope. These events include Startup and Shutdown. There are also PowerPoint application-level events such as SlideShowBegin and SlideShowEnd. These events are accessible by registering the events to the Application object in code.

Ribbon Customization

First, we need a way for the user to launch our briefing application from within PowerPoint. To provide this starting point, we will focus our attention on the Microsoft Office ribbon. The ribbon interface occupies the top portion of most of the Office applications and provides a different experience then the layered menus and toolbars of previous Office products. This interface provides a simple user experience by improving the organization of commands and providing a more graphical representation of options.

In earlier versions of Office, developer spent enormous efforts and time in writing code for custom CommandBars object to create new buttons, extend menus, and hide existing options and other customizations. By using compiled code to make these changes, developers found that the code was not portable and reusable across different Microsoft Office applications. So, the ribbon interface provides the developer with an improved programming mode for customizing it, in addition to providing enhanced end user experience.

The biggest difference in the ribbon programming mode is that customizations to the UI are done using XML. Using a custom XML file, a developer can manipulate the ribbon interface, controlling its tabs, groups and controls. This customization includes adding as well as hiding the controls in the ribbon. As the customizations are XML based, they are reusable in different projects and different Office applications. In addition to XML declarations, a class that serves the XML also provided and includes event handlers for running code in response to user interaction. VSTO does most of the plumbing of this automatically, allowing us to focus just on the customization and saves us from much more labour.

To implement the ribbon add-in in our project, first add a new item. From the Add New Item dialog box, select the Ribbon(Visual Designer) support template and name the file RibbonAddin1.cs. When the process is complete, Visual Studio will have added actually three files, RibbonAddin1.cs, RibbonAddin1.designer.cs and RibbonAddin.resx. And opens the RibbonAddin.cs in designer and the designer looks like below image. Now in designer select the tab named “TabAddIns (Built-In)” and change its Label to “Add-Ins” from the property window. Now in the designer select the “group1”  and set its Label property to “SharePoint”. Add a ToggleButton from the toolbox to this group box. Set the ToggleButton’s Label property to “Briefing” and set its image property to the appropriate one. Also set its ControlSize property to “RibbonControlSizeLarge”. Now double click that toggle button to generate its click event handler int RibbonAddIn.cs file. There in that event handler method write the following code:

Globals.ThisAddIn.CustomTaskPane.Visible = toggleButton1.Checked;

This code will take the responsibility of hiding and showing our custom task pane for our application. Of course, we need the task pane, which is nothing else but a user control named ucBriefingTaskPane. You need to add a blank user controls with the name ucBriefingTaskPane if you want to simply test the application at this stage. The following code snippet shows you how the add-in creates an instance of the custom task pane.

private CustomTaskPane _customTaskPane;
         public CustomTaskPane CustomTaskPane
            get { return _customTaskPane; }
            set { _customTaskPane = value; }

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
            _customTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(new ucBriefingTaskPane(), "Custom Briefing");
            _customTaskPane.DockPosition = MsoCTPDockPosition.msoCTPDockPositionRight;
            _customTaskPane.Width = 250;

By adding the ribbon support to the project, the user now has a way to start the briefing application, which will provide the user with a series of steps for building PowerPoint slides from SharePoint site content.

To test the application and to see how your RibbonAddin1 is integrated with the PowerPoint application, just press F5 or Click the Debug button the top toolbar. This will start the PowerPoint and adds the Add-Ins tab at the last in the PowerPoint’s Ribbon bar, as show in below image.

Clicking on the Briefing button in the toolbar will show you the CustomTaskPane at the right site, which we added by the previous code.

Implementation of the Task Pane and Wizard Steps User Controls

Our solution presents its user interface through a custom task pane that loads to the right-hand side of PowerPoint’s application window. The wizard experience for the user is a series of steps. The required logic and actions for each of the steps is written into a single user control. Primary goal of each step is as follows.
1. Get the URL of the SharePoint site and check its contents
2. Building a presentation slide for the items in the objectives list
3. Building a presentation slide for the items in the agenda list
4. Displaying a list of slide libraries so the user can import presentation slides from the site.
5. Conclusion message.

The user may not need to follow or complete all the steps. Based on the crawl of the site in step 1, it may be possible that the wizard may skip certain subsequent steps. For example, if the site does not contain any objective list, the user should not even be exposed to step 2. For this reason, our architecture compartmentalizes each of the steps into its own user control. Each step user control is responsible for displaying an interface, gathering input from the user, doing its work and reporting back to parent. The task-pane control serves as a controller, taking on the responsibility of orchestrating the step controls and collecting the information they report back that may be necessary later in the process.

To provide uniformity to the step user controls, we defined an object interface with some common elements that each control must implement. This makes it easier for our task-pane controller to interact with them since it can be guaranteed that the elements of the interface are a part of the step control.

delegate void CompletedEventHandler(object sender, EventArgs e);
public interface IWizardStep
ucBriefingTaskPane Parent { get; }
event CompletedEventHandler Completed;
void WorkComplete();
void Start();

The IWizardStep interface requires that each step user control have the following:
• A read only property that provides a reference to the task pane which is parent of it.
• An Event named Completed that will be used to inform the parent task pane that a particular step has done its work and the task pane should move on. The Completed event is created by using CompletedEventHanlder delegate.
• A WorkComplete() method used to support multithreading so that the step control can execute its work on a separate thread than the user interface one.
• A Start() method that will be called by the task pane, telling the step control that it is its turn in the process.

The task pane controller is a no user interface user control. It is simply a container control that will organize and manage step controls that present them to the user. An instance of each of the Stepn controls named wizard (where n represents the sequence number) is loaded into its controls collection. As these are loaded from code, each has its visibility off by default. In the task pane’s load event, the instance wizard1 is loaded first for start-up. Also the task pane maintains some information obtained from a step control that will be used later in the process. This includes the URL of the SharePoint site entered by user, information about whether it had any of the lists it could build content from, as well as a collection of information about the slide libraries contained in the site.

WizardStep1: Examining the Site
The wizardStep1 control is responsible for examining the SharePoint site specified by URL the user entered. For our example, the wizardStep1 control is looking to see if the site contains a list named “Objectives”, a list named “Agenda”, and information on any slide libraries. For our example, we simply created a meeting workspace to act as a test environment and populated it with some content. The objects and agenda lists are there already, created by site template by default, but you have to create at least one slide library if you want to test. Following are the steps to create a slide library to your site:

1. Go to your meeting workspace site.
2. From the Site Actions menu, choose Create.
3. In the Libraries group, click the Slide Library link.
4. Enter a suitable name for the slide library, for example, Meeting Slides.
5. Click Create button.
6. You will be redirected to a page that displays the library’s items.
7. For testing purpose, you need to upload a sample PowerPoint 2007 presentation.

Back to our step controls, this step control is designed to first ask the user for site Url of the meeting workspace. When user enters and clicks Next button, the step control tries to discover information about the lists and libraries contained in the site. SharePoint’s web services are used to get information and content of the lists in this example. To add a web reference in the project, go through the following steps.

1. In Visual Studio’s Solution Explorer window, right-click the Project name and select Add Web Reference or Add Service Reference. (If you have added any web service reference to the project earlier, then the Add Web Reference will be available otherwise select Add Service Reference.)
2. If you have Add Web Reference option and selected it then directly jump to the step 5.
3. Click Advanced… Button.
4. Click “Add Web Reference…” button.
5. Type the URL of the meeting workspace with a _vti_bin/lists.asmx ending. SharePoint’s web services are called by adding the _vti_bin folder on to the end of any site URL. This enables the web service call to discover its context and return answers specifically to the site referred to by the rest of the URL. So, for our example the URL would be like http://vpc2003:1351/_vti_bin/lists.asmx.
6. Click Go. The window below the URL will display a listing of all the methods in the Lists Web service.
7. In the Web reference name text box, change the name to WSLists.
8. Click Add Reference.

Just as the web reference added, following is the code for the Next buttons click event.

this.UseWaitCursor = true;
            WSLists.Lists listService = new BreifingCS.WSLists.Lists();
            listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
            listService.Url = this.txtSiteUrl.Text.Trim("/".ToCharArray()) + "/_vti_bin/lists.asmx";
            listService.GetListCollectionCompleted += new BreifingCS.WSLists.GetListCollectionCompletedEventHandler(listService_GetListCollectionCompleted);

One more thing to keep in mind that, when we examine the site content, this work does not interfere with the PowerPoint application’s user interface. Therefore, this work will be set up to run on a different thread. To support this, the Next button’s event handler first changes the user’s cursor to the WaitCursor. The web-service proxy is then configured to make a call under the user’s security context and to access the service through the site URL. The GetListCollectionAsync method is called so that the current thread will not wait for a response. The listService_GetListCollectionCompleted method of this step user control will be called when it receives its response.

Once the service has returned a response to the briefing add-in application, our code will execute and examines the response looking for the Objectives and Agenda lists as well as any slide library. The response from the web-service call is a string of XML that includes references to many different namespaces. Therefore this XML is loaded in XmlDocument object and XmlNamespaceNavigator is set up to easily search for the information. See the following code snippet.

XmlNode result = e.Result;
                XmlDocument doc = new XmlDocument();
                XmlNamespaceManager namespaceMrg = new XmlNamespaceManager(doc.NameTable);
                namespaceMrg.AddNamespace(ucBriefingTaskPane.SharePointNamespacePrefix, ucBriefingTaskPane.SharePointNamespaceUri);
                XmlNodeList agendaListNode = doc.SelectNodes("//sp:List[@Title='Agenda']", namespaceMrg);
                 if (agendaListNode == null || agendaListNode.Count == 0)
                    Parent.HasAgendaList = false;
                XmlNodeList objectiveListNode = doc.SelectNodes("//sp:List[@Title='Objectives']", namespaceMrg);
                 if (objectiveListNode == null || objectiveListNode.Count == 0)
                    Parent.HasObjectiveList = false;
                XmlNodeList slideLibraries = doc.SelectNodes("//sp:List[@ServerTemplate='2100']", namespaceMrg);

After gathering all the required information, this step wraps up its work and at the end the WaitCursor is turned off and the parent task pane invokes a delegate referring to the WorkComplete method. By using the this.Parent.Invoke() technique, we are returning control back to the original thread, leaving the one that performed the background processing.

WizardStep2: Building Objectives
The WizardStep2 user control is responsible for building a presentation slide containing the content in the SharePoint site’s Objectives list. The parent task pane will move control to this step by calling its Start method. In this method, first a check to Objectives list in the user’s site is done. If it did, the step makes itself visible, exposing its user interface to the user. If it didn’t this control simply calls WorkComplete to raise its Completed event, skipping itself and moving on to the next step in the process. Assuming that your site contains Objectives list, the user is presented with two options. The first is for the application to build a presentation slide that contains a bulleted list of the objective items from the site. The other option is to skip this feature and move on to the next step.

If the user chooses to have an Objectives slide built, the add-in again uses SharePoint’s lists.asmx web service and at this time the GetListItems method is used to get the objective list items. Same here, the asynchronous implementation of this method is used to prevent the main thread waiting for results. Below code snippet shows how the objective items are get using lists.asmx web service.

WSLists.Lists listService = new BreifingCS.WSLists.Lists();
            listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
            listService.Url = Parent.SiteUrl + "/_vti_bin/lists.asmx";

            XmlDocument doc = new XmlDocument();
            XmlNode nodeQuery = doc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode nodeViews = doc.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode nodeQueryOptions = doc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            nodeQueryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>";
            nodeViews.InnerXml = "<FieldRef Name='Objectives'/>";
            nodeQuery.InnerXml = "";

            listService.GetListItemsCompleted += new BreifingCS.WSLists.GetListItemsCompletedEventHandler(listService_GetListItemsCompleted);
            listService.GetListItemsAsync("Objectives", null, nodeQuery, nodeViews, null, nodeQueryOptions, null);

Once the GetListItemsAsync method is received its results, it transfers control to the GetListItemsCompleted method. Once the results are separated from other XML nodes, returned in the response, by using each object item a slide is created by the following way.

Microsoft.Office.Interop.PowerPoint.Presentation presentation =
                Microsoft.Office.Interop.PowerPoint.Slide slide = presentation.Slides.Add(presentation.Slides.Count + 1,
                slide.Shapes[1].TextFrame.TextRange.Text = "Objectives";
                StringBuilder sb = new StringBuilder();
                foreach (XmlNode node in objectiveNodeList)
                slide.Shapes[2].TextFrame.TextRange.Text = sb.ToString();

To create the slide, the code obtains a reference to the user’s active presentation and uses its slide collection’s Add method. The Add method takes 2 parameters: the index of the new slide and the layout of the slide. In this case we want to add the slide at the end of the presentation and the layout should be the one that has only a title and a text box. With the slide created, the content is placed on it by accessing its different shapes. As per our selected layout, two shapes need attention. The first is at index one and it represents the title of the slide. This is set to “Objectives”. The second shape, at index two, is populated using a StringBuilder, having each objective separated by a carriage return. Placing the carriage-return character is what gives us each objective as a bullet item. And at last, the new created slide is made active one.

WizardStep3: Building Agenda Items

The wizardStep3 control is not so different than the wizardStep2. In its start method, it also decides whether it should show itself or not. Instead of simply building another bulleted list, this slide presents the agenda items in a PowerPoint table while providing more-detailed content in the Notes portion of the slide. To get the slide set up for a table, the layout used in the Add method is ppLayoutTable. After we set the title of the presentation slide, the table is added by accessing the slide’s Shareps collection and calling its AddTable method. See the following code snippet:

Microsoft.Office.Interop.PowerPoint.Presentation presentation =
                Microsoft.Office.Interop.PowerPoint.Slide slide = presentation.Slides.Add(presentation.Slides.Count + 1,
                slide.Shapes[1].TextFrame.TextRange.Text = "Agenda";
                Microsoft.Office.Interop.PowerPoint.Shape tblAgenda = slide.Shapes.AddTable(agendaNodeList.Count, 2, -1, -1, -1, -1);
                tblAgenda.Table.Columns[1].Width = 200;
                tblAgenda.Table.Columns[2].Width = 400;
                tblAgenda.Table.FirstRow = false;

The result of our efforts is a slide that presents the time and title of each agenda item in a nicely formatted table.

WizardStep4: Integration with Slide Libraries
The step 4 user control is responsible for informing the user of the slide libraries that exists in the SharePoint site. A slide library is a new SharePoint library type that allows users to work on individual slides. This granularity allows for a great collaboration experience as users are able to work on just their portion while others edit their own portions simultaneously. The slide library also promotes slide reuse because these slides can be imported into other decks. Our assumption with this example is that the meeting workspace has at least one slide library and that there are existing slides there that should be imported into this presentation.

Like other steps, the step 4 also check if at least one slide library was discovered previously and shows itself only if that is the case. This control’s Start method includes a call to the ListOutSlideLibrariesLinks method. This method populate a panel with LinkLabel controls for each of the slide library in the site.

private void ListOutSlideLibrariesLinks()
            LinkLabel[] linkLabels = new LinkLabel[Parent.SlideLibraries.Count];
            for (int i = 0; i < Parent.SlideLibraries.Count; i++)
                linkLabels[i] = new LinkLabel();
                linkLabels[i].Location = new Point(5, 25 * i);
                linkLabels[i].LinkClicked += new LinkLabelLinkClickedEventHandler(ucWizardStep4_LinkClicked);
                linkLabels[i].LinkBehavior = LinkBehavior.AlwaysUnderline;
                linkLabels[i].Text = ((LibraryItem)Parent.SlideLibraries[i]).Name;
                LinkLabel.Link link = linkLabels[i].Links.Add(0, ((LibraryItem)Parent.SlideLibraries[i]).Name.Length);
                link.LinkData = Parent.SiteUrl + ((LibraryItem)Parent.SlideLibraries[i]).Url;

As per above code, linkControls is an array of LinkLabels containing enough controls for the number of slide libraries in the site. Within the loop, a new LinkLabel control is created for each slide library. The LinkLabel’s LinkBehavior is set to always present its text as underlined, and the actual text value is set to be the name of the slide library. When the user clicks on one of the LinkLabels, our event hanlder responds by opening the browser and directing the user to the URL of the slide library. This event handler launches the browser automatically by using the System.Diagnostics namespace and starting a process with the URL as a parameter. Once in a browser, the user will be able to use the out-of-the-box functionality of selecting slides and importing them to the current presentation. To perform this operation, the user must select the check boxes next to the slides he wants to import and click the Copy Slide to Presentation button. The user is then asked if he wants to send the selected slideds imported into the presentation we have been constructing. Note that there is also an option to receive notifications if the slide in the site were to change after this import has done. If that’s selected, each time the user opens the presentation, PowerPoint will check to see if the souce slide has been modified since the last import. If so, the user will be alerted and asked if he wishes to update the presentation.

Though there is a step5 user control, this is a last step in which presentation slides are contructed. The last step user control simply informs the user that he has completed the briefing application and that he can close the task pane by clicking the button in the ribbon user interface.

You can download the souce code for this example from here.

By Jatin Prajapati   Popularity  (8514 Views)