Problem
I am trying to create a PowerPoint presentation in C#
with Visual Studio using the Open XML SDK
.
The presentation I create contains one slide with one table with 3 rows and 2 columns.
When I try to open the PowerPoint presentation created by the program, I am presented with the following error message:
PowerPoint found a problem with content in test3.pptx.
PowerPoint can attempt to repair the presentation.
If you trust the source of this presentation, click Repair.
When I click Repair, I am presented with another error message:
PowerPoint couldn't read some content in test3.pptx - Repaired and removed it.
Please check your presentation to see if the rest looks ok.
When I click Ok and check the contents of the presentation, it is empty.
QUESTION
How should I modify the program, so users can open the presentations without problems?
- Am I using the wrong version of the
Open XML SDK
? - Is there something wrong with the code I’ve written?
- Are there tools I can use to assist me in tracking down the error?
- Other?
The version of PowerPoint I use to open the .pptx file
Microsoft® PowerPoint® for Microsoft 365 MSO (Version 2310 Build 16.0.16924.20054) 64-bit
My console project looks like this
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.20.0" />
</ItemGroup>
</Project>
My main program looks like this
var builder = new OpenXMLBuilder.Test3();
builder.Doit(args);
My source code looks like this
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using D = DocumentFormat.OpenXml.Drawing;
#region disable_warnings
// Remove unnecessary suppression
#pragma warning disable IDE0079
// Member 'x' does not access instance data and can be marked as static
#pragma warning disable CA1822
// Remove unused parameter 'x'
#pragma warning disable IDE0060
// 'using' statement can be simplified
#pragma warning disable IDE0063
// 'new' expression can be simplified
#pragma warning disable IDE0090
// Object initialization can be simplified
#pragma warning disable IDE0017
#endregion
namespace OpenXMLBuilder
{
class Test3
{
public void Doit(string[] args)
{
string filepath = "test3.pptx";
CreatePresentation(filepath);
}
public static void CreatePresentation(string filepath)
{
// Create a presentation at a specified file path.
using (PresentationDocument presentationDocument = PresentationDocument.Create(filepath, PresentationDocumentType.Presentation))
{
PresentationPart presentationPart = presentationDocument.AddPresentationPart();
presentationPart.Presentation = new Presentation();
CreateSlide(presentationPart);
}
}
private static void CreateSlide(PresentationPart presentationPart)
{
// Create the SlidePart.
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
slidePart.Slide = new Slide(new CommonSlideData(new ShapeTree()));
// Declare and instantiate the table
D.Table table = new D.Table();
// Define the columns
D.TableGrid tableGrid = new D.TableGrid();
tableGrid.Append(new D.GridColumn() { Width = 3124200 });
tableGrid.Append(new D.GridColumn() { Width = 3124200 });
// Append the TableGrid to the table
table.Append(tableGrid);
// Create the rows and cells
for (int i = 0; i < 3; i++) // 3 rows
{
D.TableRow row = new D.TableRow() { Height = 370840 };
for (int j = 0; j < 2; j++) // 2 columns
{
D.TableCell cell = new D.TableCell();
D.TextBody body = new D.TextBody(new D.BodyProperties(),
new D.ListStyle(),
new D.Paragraph(new D.Run(new D.Text($"Cell {i + 1},{j + 1}"))));
cell.Append(body);
cell.Append(new D.TableCellProperties());
row.Append(cell);
}
table.Append(row);
}
// Create a GraphicFrame to hold the table
GraphicFrame graphicFrame = new GraphicFrame();
graphicFrame.NonVisualGraphicFrameProperties = new NonVisualGraphicFrameProperties(
new NonVisualDrawingProperties() { Id = 1026, Name = "Table" },
new NonVisualGraphicFrameDrawingProperties(),
new ApplicationNonVisualDrawingProperties());
graphicFrame.Transform = new Transform(new D.Offset() { X = 0L, Y = 0L }, new D.Extents() { Cx = 0L, Cy = 0L });
graphicFrame.Graphic = new D.Graphic(new D.GraphicData(table)
{
Uri = "http://schemas.openxmlformats.org/drawingml/2006/table"
});
// Sanity check
if (slidePart.Slide.CommonSlideData == null)
throw new InvalidOperationException("CreateSlide: CommonSlideData is null");
if (slidePart.Slide.CommonSlideData.ShapeTree == null)
throw new InvalidOperationException("CreateSlide: ShapeTree is null");
// Append the GraphicFrame to the SlidePart
slidePart.Slide.CommonSlideData.ShapeTree.AppendChild(graphicFrame);
// Save the slide part
slidePart.Slide.Save();
// Create slide master
SlideMasterPart slideMasterPart = presentationPart.AddNewPart<SlideMasterPart>();
slideMasterPart.SlideMaster = new SlideMaster(new CommonSlideData(new ShapeTree()));
slideMasterPart.SlideMaster.Save();
// Create slide layout
SlideLayoutPart slideLayoutPart = slideMasterPart.AddNewPart<SlideLayoutPart>();
slideLayoutPart.SlideLayout = new SlideLayout(new CommonSlideData(new ShapeTree()));
slideLayoutPart.SlideLayout.Save();
// Create unique id for the slide
presentationPart.Presentation.SlideIdList = new SlideIdList(new SlideId()
{
Id = 256U,
RelationshipId = presentationPart.GetIdOfPart(slidePart)
});
// Set the size
presentationPart.Presentation.SlideSize = new SlideSize() { Cx = 9144000, Cy = 6858000 };
// Save the presentation
presentationPart.Presentation.Save();
}
} // class
} // namespace
2
Answers
The OpenOffice PPT problem was interesting, and I was trying around with some sample code and got the following working example to create a powerpoint using .NET 6 and DocumentFormat.OpenXml 2.20 (same version as you).
You need a pretty bit of hierarchy to be present for Powerpoint to open the file without complaints, even if some elements do not show up in the visual (like master slide, color palette, etc.). Taking out one section will lead to Powerpoint trying (successfully) to repair the presentation, which just programmatically adds the section again in the zipped XML.
I did not debug your code in detail, but I tried it and could reproduce your issue. Maybe the code sample in this post helps you: you might use it as template and then just add your custom layouts to the corresponding slide layout section. Have fun!
I was able to create a starting point similar to your (create a presentation and add a table to it).
The code is not super easy nor short, but I wasn’t able to reduce it.
Still, it produces a new powerpoint with a table in the first page!
Code took by Microsoft DOC and Microsoft sample