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);
listService.GetListCollectionAsync();
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();
doc.LoadXml(result.OuterXml);
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 =
Globals.ThisAddIn.Application.ActivePresentation;
Microsoft.Office.Interop.PowerPoint.Slide slide = presentation.Slides.Add(presentation.Slides.Count + 1,
Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutText);
slide.Shapes[1].TextFrame.TextRange.Text = "Objectives";
StringBuilder sb = new StringBuilder();
foreach (XmlNode node in objectiveNodeList)
{
sb.Append(node.Attributes["ows_Objective"].InnerText);
sb.Append(Environment.NewLine);
}
slide.Shapes[2].TextFrame.TextRange.Text = sb.ToString();
Globals.ThisAddIn.Application.ActiveWindow.View.GotoSlide(slide.SlideIndex);
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 =
Globals.ThisAddIn.Application.ActivePresentation;
Microsoft.Office.Interop.PowerPoint.Slide slide = presentation.Slides.Add(presentation.Slides.Count + 1,
Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutTable);
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()
{
pnlLinks.Controls.Clear();
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;
}
pnlLinks.Controls.AddRange(linkLabels);
}
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.