![]() |
Enterprise Systems »
Office Development »
General
Intermediate
License: The Code Project Open License (CPOL)
PowerPointCreatorBy ElmueThis C# (Visual Studio 2003) project creates PowerPoint presentations based on XML templates which are filled with dynamic data. |
C#, XML.NET 1.1, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
The Analyzer allows to write all properties of all Shapes in an existing PowerPoint Presentation into XML files.
My first experiments using PowerPoint 2003 failed because PP 2003 is !FULL! of ugly bugs.
You set the width of a border of a table cell. No problem. Afterwards you try to set the color of the same border: result = Exception 0x800A01A8
Then you try to do it in the reverse order: First set the color. No problem. Then set the width: result = Exception 0x800A01A8. This exception has no documentation in MSDN and in the internet you find hundreds of people with the same problem but no solution.
There were a lot of other things which did not work in PP 2003 and all had one thing in common: they were extremely strange and did not make any sense.
I wasted two entire days searching for a workaround: without success. Finally I found the solution: Using PowerPoint 2007 which does not have these bugs anymore.
When I started the project, I didn't want to use PowerPoint 2007 because I wanted to create PPP documents which can also be played on PP 2003. But then I found that my documents created on PP 2007 will also play on PP 2002 and PP 2003 without problems.
IMPORTANT: Read in the last chapter what you have to install additionally to PP 2007!
This project demonstrates the creation of a Sales Report of a fictitious company "Ipsum Colors Inc." which sells paints.
The following animation shows a PowerPoint Presentation consisting of 5 slides which have been created from scratch with PowerPointCreator:
Let's have a look at how to create the first page (the start slide):
string s_TemplatePath = Directory.GetCurrentDirectory() + "\\Templates";
PPPcreator i_PppCreator = new PPPcreator(s_TemplatePath, true);
Hashtable i_Replacements = new Hashtable();
i_Replacements["CurrentDate"] = DateTime.Today.ToString("dd. MMMM yyyy");
i_PppCreator.InsertTemplateSlide(-1, null, "Template_StartSlide.xml", i_Replacements);
It's really that simple! These 5 lines of code create an entire PowerPoint slide! You specify an XML template "Template_StartSlide.xml" and a hashtable with replacements for all dynamic data which is to be inserted into the template (here the current date).
The second parameter of the PPPcreator constructor (true) specifies the creation mode.
true -> PowerPoint opens and you see the creation process "live" on the screen as if you would add all the elements manually.
false -> PowerPoint runs minimized in the taskbar without a visible window. This mode is faster.
You can also insert new slides into an already existing presentation:
i_PppCreator.LoadPresentation (@"C:\My Documents\....\SalesReport.ppt");
i_PppCreator.InsertTemplateSlide(5, "Template_Background.pot", "Template_XYZ.xml",
i_Replacements);
The first parameter of InsertTemplateSlide() specifies the zero based insert position of the new slide.
The second parameter of InsertTemplateSlide() specifies an optional PowerPoint Template. (*.pot)
From this SlideMaster template only the basic layout (like header and footer) will be loaded, not the content!
The structure of the XML templates is very similar to HTML files. The templates completely define how the resulting Presentation will look. They contain two main tags:
The Shapes tag contains all PowerPoint Shapes you want to insert into the document like TextBoxes, Tables, Pictures or Lines.
The Styles tag contains definitions of how these elements will look like, for example their color and font size.
ATTENTION:
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="TitleBox" Name="Title">
Sales Report</Textbox>
<Picture Top="155" Left="120" Width="250" Height="195">Company_Logo.gif</Picture>
<Table Top="75" Left="45" ColumnWidths="100,120,100,150" MaxHeight="405">
<Row Height="20">
<Cell Style="CellCommon,CellDark">First Cell</Cell>
<Cell Style="CellCommon,CellBright">Second Cell</Cell>
<Cell Style="CellCommon,CellBright" ColSpan="2">Third and Fourth Cell</Cell>
</Row>
</Table>
<Line BeginX="120" BeginY="465" EndX="120" EndY="494" Style="GreenLine" />
</Shapes>
All Shapes use absolute positioning, so the attributes Top and Left are mandatory. The Shapes are drawn in the order in which they appear in the XML file. So if you want to put text on top of a picture you have to define the picture first.
Every Shape can have an optional Name attribute. This name is similar to an ID or Name tag in HTML. It is stored invisible in the PPP document and may be useful to locate a Shape if you want to modify the document later.
You don't need to specify the Height attribute for a Textbox as the height depends on the text which you put into the box. The height is only required if the textbox has a visible border or a background color and is bigger than the text.
All Pictures are loaded from the Template folder which you have specified in the constructor of PPPcreator.
The Table in the above example has 4 columns whose widths (100,120,100,150) you specify in the attribute ColumnWidths.
The Height attribute for table rows is optional. If it is missing, the row's content will define its height. Cells can be combined with their right neighbour using the ColSpan attribute.
As the cells in the above example show, you can specify multiple styles separated by a comma.
In the Styles section of the XML file (see below):
CellCommon contains definitions for all cells. CellBright contains only the color definitions for the white cells. CellDark contains only the color definitions for the blue cells. The MaxHeight attribute for the table defines when its content will be broken onto the next slide. PowerPoint does not do that automatically (like Word does). If the table becomes too high, PowerPointCreator removes as many words from the last table cell as is required to make the text fit on that slide. After that a new slide is appended which receives the rest of the table. To optically show the continuation of a table, it's border becomes dashed:
<Styles>
<TitleBox Shape.TextFrame.MarginLeft="10"
Shape.TextFrame.TextRange.Font.Name="Arial"
Shape.TextFrame.TextRange.Font.Size="22"
Shape.TextFrame.TextRange.Font.Bold="true"
Shape.TextFrame.TextRange.Font.Color.RGB="#373C71"
Shape.TextFrame.TextRange.ParagraphFormat.Alignment="ppAlignCenter"
/>
<CellCommon Borders.ppBorderTop.Weight="1"
Borders.ppBorderBottom.Weight="1"
Borders.ppBorderLeft.Weight="1"
Borders.ppBorderRight.Weight="1"
Borders.ppBorderLeft.ForeColor.RGB="#373C71"
Borders.ppBorderRight.ForeColor.RGB="#373C71"
Borders.ppBorderBottom.ForeColor.RGB="#373C71"
Shape.TextFrame.TextRange.Font.Name="Arial"
Shape.TextFrame.TextRange.Font.Size="10"
Shape.Fill.Solid="true"
/>
<CellDark Borders.ppBorderTop.ForeColor.RGB="#FFFFFF"
Shape.TextFrame.TextRange.Font.Bold="true"
Shape.TextFrame.TextRange.Font.Color.RGB="#FFFFFF"
Shape.Fill.ForeColor.RGB="#373C71"
/>
etc....
</Shape>
All entries have exactly the same name as the corresponding objects in the namespace PowerPoint.
Don't try to abbreviate these attributes!!
For example: A cell may specify border settings (LineFormat), also a row and a Line use the same properties. There are multiple objects which allow you to specify a ForeColor or BackColor. You will run into a big confusion if you try to simplify these long properties!
If you need additional properties which are not yet supported by the PPPcreator class, you have to add them on your own. I would have liked to use Reflection to set the properties but this is not possible as Microsoft.Office.Interop.PowerPoint is a COM object which does not support Reflection. So each and every property must be set separately in a long switch() statement.
When you define the cell borders, you have to be careful. For each cell you can specify width, color, etc.. for it's top border, bottom border, left border and right border separately. But each cell shares its borders with its neighbours...
...and as a table is painted from top to bottom, the settings of the bottom border of a cell will be overwritten with the settings of the top border of the following row.
To obtain a table as you see in this image the cell C must define a top border which is white, but Cell B must define a top border which is blue, while the bottom border of all Cells A-C may be defined as ANYthing which will be ignored as the next row overwrites it with its own settings!
The bottom border will ONLY be of importance in the very last row.
The right border will ONLY be of importance in the very last column.
For all other cells only the top and the left border have importance.
If you study the file "Template_Table.xml" thoroughly, you will understand how it works:
CellDark defines a white top border. CellTopDark defines a blue top border. Style="CellDark,CellTopDark" the order of the styles matters! That means that the TopBorder color in CellTopDark will overwrite the definition in CellDark!
Cell B:
<Cell Style="CellCommon,CellDark,CellTopDark">Priority</Cell>
Cell C:
<Cell Style="CellCommon,CellDark">Finished</Cell>
The Replacements make the templates really dynamic. To insert a dynamic title into a PP slide write in the XML file:
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="TitleBox">%Title%</Textbox>
</Shapes>
The data to be inserted may come from a database, you can read it from an XML file, or get it from wherever you like. You have to store it into a hashtable and pass it to PPPcreator.
Hashtable i_Replacements = new Hashtable();
i_Replacements["Title"] = "Sales Report";
i_PppCreator.InsertTemplateSlide(-1, null, "Template_Table.xml", i_Replacements);
You can do the same with text in table cells or picture files.
Also, the values of Attributes can be defined dynamically. For example, if your template defines different title styles, you can decide at runtime which style to use for the title:
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="%TitleStyle%">Sales Report</Textbox>
</Shapes>
Another feature is the ability to write formatted text into a PowerPoint TextBox or TableCell.
The Replacements may contain HTML code if it is enclosed between <HTML> and </HTML>:
i_Replacements["Summary"] = "<Html><b><big>Lorem ipsum</big></b></Html>";
You put the HTML code directly into the XML file:
<Textbox Top="60" Left="90" Width="580" Style="TitleBox" Name="Title">
<Html>
Sales Report <BR />
<Font Color="#000088">Business Statistic</Font>
<small>half-way 2008</small>
</Html>
</Textbox>
<BR>, <LI>, etc.) <DIV> with a </div> TextRangeFormat for allowed tags. And what if I want to create a list with a variable count of rows (for example from a database)? No problem!
Write in the XML file:
<Shapes>
<Table Top="100" Left="65" ColumnWidths="360,77,77,77" MaxHeight="405">
<Row Height="15" DataSource="SalesData">
<Cell Style="xyz">%SalesData#Product%</Cell>
<Cell Style="xyz">%SalesData#Sold%</Cell>
<Cell Style="xyz">%SalesData#Profit%</Cell>
<Cell Style="xyz">%SalesData#Percent%</Cell>
</Row>
</Table>
</Shapes>
The row will be repeated as often as your DataSource has row entries. The replacements must be of the form %DataSourceName#ColumnName%. In the C# code, write:
DataSource i_SalesData = new DataSource(new string[]{ "Product", "Sold", "Profit",
"Percent" });
i_SalesData.AddRow(new string[]{"LA553 - Gallon Ultra Premium Flat Wall Paint",
"353.912", "$3.267.000", "25,7%"});
i_SalesData.AddRow(new string[]{"IN965 - Interior Wall Paint 10 litre Acryl",
"270.733", "$2.332.000", "22,4%"});
etc...
Hashtable i_Replacements = new Hashtable();
i_Replacements["SalesData"] = i_SalesData;
i_PppCreator.InsertTemplateSlide(-1, "Template_Background.pot",
"Template_DynamicList.xml", i_Replacements);
The DataSource class is a special class designed to hold table data for dynamic list creation. The names of the columns are defined in the DataSource constructor and must obviously have the same names as the XML entries.
Above you will find an example of everything I've explained in the PowerPointCreator project.
The second part of the application is the PowerPoint Analyzer.
You specify any existing PPP or PPS file and the Analyzer creates an XML file for each Slide it finds in it.
There are hundreds of properties which a Shape can have.
To avoid an endless XML file the analyzer has built in intelligence:
TextBox, it has several default properties like Shape.Fill.RotateWithObject="msoFalse". TextBoxes, all TableCells, etc... for their common properties and generates an XML node under <styles> which it stores the common properties. So they are not written 50 times for 50 table cells. PropertyInfo.CanWrite=false), it is skipped. There are several Shape properties which are read-only. It does not make sense to store them in the XML file as they later cannot be assigned in PPPcreator. Shape.TextFrame and Shape.TextFrame2 which is also eliminated. The result is a handy XML file which can be used as input for the Creator.
Due to the incredible complexity of the PowerPoint API, you must be aware that the generated XML file will probably require manual editing.
Analyzer: It analyzes ANY PowerPoint presentation using its tricky Pseudo-Refection.
Creator: In the current version 5.0 ready to generate Tables, Lines, TextBoxes and Pictures.
But AutoShapes and Groups are premature / not implemented.
PowerPoint is very slow. When you create a presentation "live", you will see how it draws every single table cell and prints the text.
PowerPoint is quite primitive (like the entire Office package). For example, it does not allow you to put a picture into a table cell. This is not possible. Also you cannot append a table row to the end of a table. If the previous row has merged cells (uses ColSpan) the new row would merge the same cells although you never did program that. For all these things PPPcreator has workarounds built in.
A documentation for the PowerPoint API does not exist. What you find in the MSDN is ridiculous. You have to find out everything by trial and error.
Some functions which exist in the PowerPoint API are not implemented. (for example, Slide.Shapes.AddDiagram(...)).
All PowerPoint presentations use the odd coordinate system of 720 x 540 pixels. To ease the definition of coordinates when creating the XML file, PowerPointCreator draws a helper grid when compiled in Debug mode. Every 20 pixels, a dashed line is drawn and every 100 units a solid line:
You will find a very clean and well structured C# source code with plenty of comments, written by a very experienced programmer. The code is reusable, so you can easily put it into your own projects:
PPPcreator encapsulates all the PowerPoint creation stuff DataSource stores Dynamic List data XML eases XML file management Functions contains a bunch of helper functions To compile or run this project:
Obviously you must have PowerPoint XP installed.
VB is required although this is a C# project!!
The ".NET Programmability Support" which you find in the Office XP installer under "PowerPoint" installs the files Office.dll and Microsoft.Office.Interop.PowerPoint.dll into the Global Assembly Cache.
But you don't need to install this because I have put these tiny DLLs into the same folder as the EXE and compiled the EXE to run with these 'local' DLLs if they are not found in the GAC. So the program will also run on a computer where only PowerPoint XP is installed without these DLLs in the GAC. This avoids crashes, unnecessary problems, frustrated users and a lot of work for the support.
The current version 2.0 contains a lot of useful functionality. Probably future versions, which will be published on CodeProject, will contain more functionality like dynamic generation of diagrams, etc..
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 19 Jan 2009 Editor: Sean Ewington |
Copyright 2008 by Elmue Everything else Copyright © CodeProject, 1999-2009 Web17 | Advertise on the Code Project |