Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Creating Powerpoint Table using ‘OpenXML’ with XAML Applications

4.43/5 (4 votes)
18 Oct 2014CPOL1 min read 22.2K  
A generic way of adding a table to Powerpoint using OpenXML

I was recently struck with creating a Powerpoint presentation with a table in it using OpenXml, Googling did not help me a lot, so below is the solution.

I need to mention a thing here, I was struck ‘n’ number of times in between and a tool named ‘Open XML SDK 2.5 for Microsoft Office’ helped me solve the problems. I would seriously recommend this tool if you are trying to create your own structure using OpenXML. This accurately tells where the problem lies and what is expected and missing. (It isn't that easy to use this though!!!). It shows an XML node and you need to find that and add/remove as the tool tells.

You can download it from here.

Below, we will be able to see how to use OpenXml to create a Powerpoint presentation with table in it.

Hope you have prior knowledge of how to create a WCF service :0/ .

Kindly reference or add namespaces as below. You will also need to download OpenXml DLLs from Nuget.

C#
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using P14 = DocumentFormat.OpenXml.Office2010.PowerPoint;
using System.Collections.Generic;
using System.Text;
using P = DocumentFormat.OpenXml.Presentation;
using D = DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Presentation;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using System.IO;
using System.ComponentModel;   

Our Service will look as below:

C#
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

[KnownType(typeof(Configuration))]
public class Service
{
    //location where powerpoint template file is available. Here bin directory is used.
    //however the location can be set in config file and read it
    //from there if the template ppt should not be a part of the project
    string templateFilePath = Path.Combine(string.Format("{0}\\bin",
    AppDomain.CurrentDomain.BaseDirectory), "Template.pptx");
    //location where a copy of template file
    //to be created.(will be deleted once the byte array is created)
    string tempFilePath = Path.Combine(string.Format("{0}\\bin",
    AppDomain.CurrentDomain.BaseDirectory),
    string.Format("Template_{0}.pptx", new Guid()));

    /// <summary>
    /// Append Table into Last Slide
    /// </summary>
    /// <param name="presentationDocument"></param>
    [OperationContract]
    public byte[] CreateTableInLastSlide(List<Configuration> configurations)
    {
        CreatePresentation();

        PresentationDocument presentationDocument = PresentationDocument.Open(tempFilePath, true);

        // Get the presentation Part of the presentation document
        PresentationPart presentationPart = presentationDocument.PresentationPart;

        // Get the Slide Id collection of the presentation document
        var slideIdList = presentationPart.Presentation.SlideIdList;

        if (slideIdList == null)
        {
            throw new NullReferenceException
            ("The number of slide is empty,
            please select a ppt with a slide at least again");
        }

        // Get all Slide Part of the presentation document
        var list = slideIdList.ChildElements
                    .Cast<SlideId>()
                    .Select(x => presentationPart.GetPartById(x.RelationshipId))
                    .Cast<SlidePart>();

        // Get the last Slide Part of the presentation document
        var tableSlidePart = (SlidePart)list.Last();

        P.GraphicFrame graphicFrame = tableSlidePart.Slide.CommonSlideData.ShapeTree.AppendChild
        (new P.GraphicFrame(new P.NonVisualGraphicFrameProperties
            (new P.NonVisualDrawingProperties() { Id = 1, Name = "xyz" },
            new P.NonVisualGraphicFrameDrawingProperties(),
            new ApplicationNonVisualDrawingProperties())));

        graphicFrame.Transform = new Transform(new D.Offset() { X = 10, Y = 10 });

        graphicFrame.Graphic = new D.Graphic(new D.GraphicData(GenerateTable(configurations))
        { Uri = "http://schemas.openxmlformats.org/drawingml/2006/table" });
        presentationPart.Presentation.Save();
        presentationDocument.Close();
        byte[] pptByte = File.ReadAllBytes(tempFilePath);
        File.Delete(tempFilePath);
        return pptByte;
    }

    /// <summary>
    /// Generate Table as below order:
    /// a:tbl(Table) ->a:tr(TableRow)->a:tc(TableCell)
    /// We can return TableCell object with CreateTextCell method
    /// and Append the TableCell object to TableRow
    /// </summary>
    /// <returns>Table Object</returns>

    private D.Table GenerateTable(List<Configuration> configurations)
    {
        // Declare and instantiate table
        D.Table table = new D.Table();

        // Specify the required table properties for the table
        D.TableProperties tableProperties = new D.TableProperties()
        { FirstRow = true, BandRow = true };
        D.TableStyleId tableStyleId = new D.TableStyleId();
        tableStyleId.Text = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";

        tableProperties.Append(tableStyleId);

        // Declare and instantiate tablegrid and columns depending on your columns
        D.TableGrid tableGrid1 = new D.TableGrid();
        D.GridColumn gridColumn1 = new D.GridColumn() { Width = 1048000L };
        D.GridColumn gridColumn2 = new D.GridColumn() { Width = 1048000L };

        tableGrid1.Append(gridColumn1);
        tableGrid1.Append(gridColumn2);

        table.Append(tableProperties);
        table.Append(tableGrid1);

        D.TableRow tableRow1 = new D.TableRow() { Height = 370840L };
        var list = GetPropertiesNameOfClass(configurations.FirstOrDefault());
        foreach (var item in list)
        {
            tableRow1.Append(CreateTextCell(item.ToString()));
        }
        table.Append(tableRow1);

        foreach (var config in configurations)
        {
            D.TableRow tableRow = new D.TableRow() { Height = 370840L };
            foreach (var prop in config.GetType().GetProperties())
            {
                tableRow.Append(CreateTextCell(prop.GetValue(config, null).ToString()));
            }
            table.Append(tableRow);
        }

        return table;
    }

    public List<string> GetPropertiesNameOfClass(object pObject)
    {
        List<string> propertyList = new List<string>();
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(pObject);

        foreach (PropertyDescriptor property in properties)
        {
                propertyList.Add(property.DisplayName);
        }

        return propertyList;
    }

    /// <summary>
    /// Create table cell with the below order:
    /// a:tc(TableCell)->a:txbody(TextBody)->a:p(Paragraph)->a:r(Run)->a:t(Text)
    /// </summary>
    /// <param name="text">Inserted Text in Cell</param>
    /// <returns>Return TableCell object</returns>

    private D.TableCell CreateTextCell(string text)
    {
        if (string.IsNullOrEmpty(text))
        {
            text = string.Empty;
        }

        // Declare and instantiate the table cell
        // Create table cell with the below order:
        // a:tc(TableCell)->a:txbody(TextBody)->a:p(Paragraph)->a:r(Run)->a:t(Text)
        D.TableCell tableCell = new D.TableCell();

        //  Declare and instantiate the text body
        D.TextBody textBody = new D.TextBody();
        D.BodyProperties bodyProperties = new D.BodyProperties();
        D.ListStyle listStyle = new D.ListStyle();

        D.Paragraph paragraph = new D.Paragraph();
        D.Run run = new D.Run();
        D.RunProperties runProperties = new D.RunProperties()
        { Language = "en-US", Dirty = false };
        D.Text text2 = new D.Text();
        text2.Text = text;
        run.Append(runProperties);
        run.Append(text2);
        D.EndParagraphRunProperties endParagraphRunProperties =
        new D.EndParagraphRunProperties() { Language = "en-US", Dirty = false };

        paragraph.Append(run);
        paragraph.Append(endParagraphRunProperties);
        textBody.Append(bodyProperties);
        textBody.Append(listStyle);
        textBody.Append(paragraph);

        D.TableCellProperties tableCellProperties = new D.TableCellProperties();
        tableCell.Append(textBody);
        tableCell.Append(tableCellProperties);

        return tableCell;
    }

    [OperationContract]
    public void CreatePresentation()
    {
        // Create a presentation at a specified file path.
        // The presentation document type is pptx, by default.
        PresentationDocument presentationDoc = PresentationDocument.Create
                (tempFilePath, PresentationDocumentType.Presentation);
        PresentationPart presentationPart = presentationDoc.AddPresentationPart();
        presentationPart.Presentation = new Presentation();

        CreatePresentationParts(presentationPart);

        //Close the presentation handle
        presentationDoc.Close();
    }

    private void CreatePresentationParts(PresentationPart presentationPart)
    {
        SlideMasterIdList slideMasterIdList1 = new SlideMasterIdList(new SlideMasterId()
        { Id = (UInt32Value)2147483648U, RelationshipId = "rId1" });
        SlideIdList slideIdList1 = new SlideIdList(new SlideId()
        { Id = (UInt32Value)256U, RelationshipId = "rId2" });
        SlideSize slideSize1 = new SlideSize()
        { Cx = 9144000, Cy = 6858000, Type = SlideSizeValues.Screen4x3 };
        NotesSize notesSize1 = new NotesSize()
        { Cx = 6858000, Cy = 9144000 };
        DefaultTextStyle defaultTextStyle1 = new DefaultTextStyle();

        presentationPart.Presentation.Append
        (slideMasterIdList1, slideIdList1, slideSize1, notesSize1, defaultTextStyle1);

        SlidePart slidePart1;
        SlideLayoutPart slideLayoutPart1;
        SlideMasterPart slideMasterPart1;
        ThemePart themePart1;


        slidePart1 = CreateSlidePart(presentationPart);
        slideLayoutPart1 = CreateSlideLayoutPart(slidePart1);
        slideMasterPart1 = CreateSlideMasterPart(slideLayoutPart1);
        themePart1 = CreateTheme(slideMasterPart1);

        slideMasterPart1.AddPart(slideLayoutPart1, "rId1");
        presentationPart.AddPart(slideMasterPart1, "rId1");
        presentationPart.AddPart(themePart1, "rId5");
    }

    private SlidePart CreateSlidePart(PresentationPart presentationPart)
    {
        SlidePart slidePart1 = presentationPart.AddNewPart<SlidePart>("rId2");
        slidePart1.Slide = new Slide(
                new CommonSlideData(
                    new ShapeTree(
                        new P.NonVisualGroupShapeProperties(
                            new P.NonVisualDrawingProperties()
                            { Id = (UInt32Value)1U, Name = "" },
                            new P.NonVisualGroupShapeDrawingProperties(),
                            new ApplicationNonVisualDrawingProperties()),
                        new GroupShapeProperties(new D.TransformGroup()),
                        new P.Shape(
                            new P.NonVisualShapeProperties(
                                new P.NonVisualDrawingProperties()
                                { Id = (UInt32Value)2U, Name = "Title 1" },
                                new P.NonVisualShapeDrawingProperties(new D.ShapeLocks()
                                { NoGrouping = true }),
                                new ApplicationNonVisualDrawingProperties(new PlaceholderShape())),
                            new P.ShapeProperties(),
                            new P.TextBody(
                                new D.BodyProperties(),
                                new D.ListStyle(),
                                new D.Paragraph(new D.EndParagraphRunProperties()
                                { Language = "en-US" }))))),
                new ColorMapOverride(new D.MasterColorMapping()));
        return slidePart1;
    }

    private SlideLayoutPart CreateSlideLayoutPart(SlidePart slidePart1)
    {
        SlideLayoutPart slideLayoutPart1 =
        slidePart1.AddNewPart<SlideLayoutPart>("rId1");
        SlideLayout slideLayout = new SlideLayout(
        new CommonSlideData(new ShapeTree(
          new P.NonVisualGroupShapeProperties(
          new P.NonVisualDrawingProperties() { Id = (UInt32Value)1U, Name = "" },
          new P.NonVisualGroupShapeDrawingProperties(),
          new ApplicationNonVisualDrawingProperties()),
          new GroupShapeProperties(new D.TransformGroup()),
          new P.Shape(
          new P.NonVisualShapeProperties(
            new P.NonVisualDrawingProperties() { Id = (UInt32Value)2U, Name = "" },
            new P.NonVisualShapeDrawingProperties(new D.ShapeLocks() { NoGrouping = true }),
            new ApplicationNonVisualDrawingProperties(new PlaceholderShape())),
          new P.ShapeProperties(),
          new P.TextBody(
            new D.BodyProperties(),
            new D.ListStyle(),
            new D.Paragraph(new D.EndParagraphRunProperties()))))),
        new ColorMapOverride(new D.MasterColorMapping()));
        slideLayoutPart1.SlideLayout = slideLayout;
        return slideLayoutPart1;
    }

    private SlideMasterPart CreateSlideMasterPart(SlideLayoutPart slideLayoutPart1)
    {
        SlideMasterPart slideMasterPart1 =
        slideLayoutPart1.AddNewPart<SlideMasterPart>("rId1");
        SlideMaster slideMaster = new SlideMaster(
        new CommonSlideData(new ShapeTree(
          new P.NonVisualGroupShapeProperties(
          new P.NonVisualDrawingProperties() { Id = (UInt32Value)1U, Name = "" },
          new P.NonVisualGroupShapeDrawingProperties(),
          new ApplicationNonVisualDrawingProperties()),
          new GroupShapeProperties(new D.TransformGroup()),
          new P.Shape(
          new P.NonVisualShapeProperties(
            new P.NonVisualDrawingProperties()
            { Id = (UInt32Value)2U, Name = "Title Placeholder 1" },
            new P.NonVisualShapeDrawingProperties(new D.ShapeLocks()
            { NoGrouping = true }),
            new ApplicationNonVisualDrawingProperties(new PlaceholderShape()
            { Type = PlaceholderValues.Title })),
          new P.ShapeProperties(),
          new P.TextBody(
            new D.BodyProperties(),
            new D.ListStyle(),
            new D.Paragraph())))),
        new P.ColorMap() { Background1 = D.ColorSchemeIndexValues.Light1,
        Text1 = D.ColorSchemeIndexValues.Dark1, Background2 = D.ColorSchemeIndexValues.Light2,
        Text2 = D.ColorSchemeIndexValues.Dark2, Accent1 = D.ColorSchemeIndexValues.Accent1,
        Accent2 = D.ColorSchemeIndexValues.Accent2, Accent3 = D.ColorSchemeIndexValues.Accent3,
        Accent4 = D.ColorSchemeIndexValues.Accent4, Accent5 = D.ColorSchemeIndexValues.Accent5,
        Accent6 = D.ColorSchemeIndexValues.Accent6, Hyperlink = D.ColorSchemeIndexValues.Hyperlink,
        FollowedHyperlink = D.ColorSchemeIndexValues.FollowedHyperlink },
        new SlideLayoutIdList(new SlideLayoutId()
        { Id = (UInt32Value)2147483649U, RelationshipId = "rId1" }),
        new TextStyles(new TitleStyle(), new BodyStyle(), new OtherStyle()));
        slideMasterPart1.SlideMaster = slideMaster;

        return slideMasterPart1;
    }
}

You can further add theming to your PPT as below:

C#
private ThemePart CreateTheme(SlideMasterPart slideMasterPart1)
{
    ThemePart themePart1 = slideMasterPart1.AddNewPart<themepart>("rId5");
    D.Theme theme1 = new D.Theme() { Name = "Office Theme" };

    D.ThemeElements themeElements1 = new D.ThemeElements(
    new D.ColorScheme(
      new D.Dark1Color(new D.SystemColor()
      { Val = D.SystemColorValues.WindowText, LastColor = "000000" }),
      new D.Light1Color(new D.SystemColor()
      { Val = D.SystemColorValues.Window, LastColor = "FFFFFF" }),
      new D.Dark2Color(new D.RgbColorModelHex() { Val = "1F497D" }),
      new D.Light2Color(new D.RgbColorModelHex() { Val = "EEECE1" }),
      new D.Accent1Color(new D.RgbColorModelHex() { Val = "4F81BD" }),
      new D.Accent2Color(new D.RgbColorModelHex() { Val = "C0504D" }),
      new D.Accent3Color(new D.RgbColorModelHex() { Val = "9BBB59" }),
      new D.Accent4Color(new D.RgbColorModelHex() { Val = "8064A2" }),
      new D.Accent5Color(new D.RgbColorModelHex() { Val = "4BACC6" }),
      new D.Accent6Color(new D.RgbColorModelHex() { Val = "F79646" }),
      new D.Hyperlink(new D.RgbColorModelHex() { Val = "0000FF" }),
      new D.FollowedHyperlinkColor(new D.RgbColorModelHex()
      { Val = "800080" })) { Name = "Office" },
      new D.FontScheme(
      new D.MajorFont(
      new D.LatinFont() { Typeface = "Calibri" },
      new D.EastAsianFont() { Typeface = "" },
      new D.ComplexScriptFont() { Typeface = "" }),
      new D.MinorFont(
      new D.LatinFont() { Typeface = "Calibri" },
      new D.EastAsianFont() { Typeface = "" },
      new D.ComplexScriptFont() { Typeface = "" }))
      { Name = "Office" },
      new D.FormatScheme(
      new D.FillStyleList(
      new D.SolidFill(new D.SchemeColor()
      { Val = D.SchemeColorValues.PhColor }),
      new D.GradientFill(
        new D.GradientStopList(
        new D.GradientStop(new D.SchemeColor(new D.Tint()
        { Val = 50000 },
          new D.SaturationModulation() { Val = 300000 })
          { Val = D.SchemeColorValues.PhColor }) { Position = 0 },
        new D.GradientStop(new D.SchemeColor(new D.Tint()
        { Val = 37000 },
         new D.SaturationModulation() { Val = 300000 })
         { Val = D.SchemeColorValues.PhColor }) { Position = 35000 },
        new D.GradientStop(new D.SchemeColor(new D.Tint()
        { Val = 15000 },
         new D.SaturationModulation() { Val = 350000 })
         { Val = D.SchemeColorValues.PhColor }) { Position = 100000 }
        ),
        new D.LinearGradientFill() { Angle = 16200000, Scaled = true }),
      new D.NoFill(),
      new D.PatternFill(),
      new D.GroupFill()),
      new D.LineStyleList(
      new D.Outline(
        new D.SolidFill(
        new D.SchemeColor(
          new D.Shade() { Val = 95000 },
          new D.SaturationModulation() { Val = 105000 })
          { Val = D.SchemeColorValues.PhColor }),
        new D.PresetDash() { Val = D.PresetLineDashValues.Solid })
      {
          Width = 9525,
          CapType = D.LineCapValues.Flat,
          CompoundLineType = D.CompoundLineValues.Single,
          Alignment = D.PenAlignmentValues.Center
      },
      new D.Outline(
        new D.SolidFill(
        new D.SchemeColor(
          new D.Shade() { Val = 95000 },
          new D.SaturationModulation() { Val = 105000 })
          { Val = D.SchemeColorValues.PhColor }),
        new D.PresetDash() { Val = D.PresetLineDashValues.Solid })
      {
          Width = 9525,
          CapType = D.LineCapValues.Flat,
          CompoundLineType = D.CompoundLineValues.Single,
          Alignment = D.PenAlignmentValues.Center
      },
      new D.Outline(
        new D.SolidFill(
        new D.SchemeColor(
          new D.Shade() { Val = 95000 },
          new D.SaturationModulation() { Val = 105000 })
          { Val = D.SchemeColorValues.PhColor }),
        new D.PresetDash() { Val = D.PresetLineDashValues.Solid })
      {
          Width = 9525,
          CapType = D.LineCapValues.Flat,
          CompoundLineType = D.CompoundLineValues.Single,
          Alignment = D.PenAlignmentValues.Center
      }),
      new D.EffectStyleList(
      new D.EffectStyle(
        new D.EffectList(
        new D.OuterShadow(
          new D.RgbColorModelHex(
          new D.Alpha() { Val = 38000 }) { Val = "000000" })
          { BlurRadius = 40000L, Distance = 20000L,
          Direction = 5400000, RotateWithShape = false })),
      new D.EffectStyle(
        new D.EffectList(
        new D.OuterShadow(
          new D.RgbColorModelHex(
          new D.Alpha() { Val = 38000 }) { Val = "000000" })
          { BlurRadius = 40000L, Distance = 20000L,
          Direction = 5400000, RotateWithShape = false })),
      new D.EffectStyle(
        new D.EffectList(
        new D.OuterShadow(
          new D.RgbColorModelHex(
          new D.Alpha() { Val = 38000 }) { Val = "000000" })
          { BlurRadius = 40000L, Distance = 20000L,
          Direction = 5400000, RotateWithShape = false }))),
      new D.BackgroundFillStyleList(
      new D.SolidFill(new D.SchemeColor()
      { Val = D.SchemeColorValues.PhColor }),
      new D.GradientFill(
        new D.GradientStopList(
        new D.GradientStop(
          new D.SchemeColor(new D.Tint() { Val = 50000 },
            new D.SaturationModulation() { Val = 300000 })
            { Val = D.SchemeColorValues.PhColor }) { Position = 0 },
        new D.GradientStop(
          new D.SchemeColor(new D.Tint() { Val = 50000 },
            new D.SaturationModulation() { Val = 300000 })
            { Val = D.SchemeColorValues.PhColor }) { Position = 0 },
        new D.GradientStop(
          new D.SchemeColor(new D.Tint() { Val = 50000 },
            new D.SaturationModulation() { Val = 300000 })
            { Val = D.SchemeColorValues.PhColor }) { Position = 0 }),
        new D.LinearGradientFill() { Angle = 16200000, Scaled = true }),
      new D.GradientFill(
        new D.GradientStopList(
        new D.GradientStop(
          new D.SchemeColor(new D.Tint() { Val = 50000 },
            new D.SaturationModulation() { Val = 300000 })
            { Val = D.SchemeColorValues.PhColor }) { Position = 0 },
        new D.GradientStop(
          new D.SchemeColor(new D.Tint() { Val = 50000 },
            new D.SaturationModulation() { Val = 300000 })
            { Val = D.SchemeColorValues.PhColor }) { Position = 0 }),
        new D.LinearGradientFill() { Angle = 16200000, Scaled = true })))
        { Name = "Office" });

    theme1.Append(themeElements1);
    theme1.Append(new D.ObjectDefaults());
    theme1.Append(new D.ExtraColorSchemeList());

    themePart1.Theme = theme1;
    return themePart1;
}

The Configuration data contract is as shown below. I have 'display name' attribute associated to it so that I can show the same in my presentation Table header.

C#
[DataContract]
    public class Configuration
    {
        [DataMember]
        [DisplayName("Value")]
        public string Value { get; set; }

        [DataMember]
        [DisplayName("Name")]
        public decimal Name{ get; set; }
    }

Now we will look at the client side:

You can now add the service reference (as you do normally) and write the below code.

C#
ServiceClient proxy = new ServiceClient();
Stream stream;
SaveFileDialog objSFD;
private void btnPowerpoint_Click(object sender, RoutedEventArgs e)
{
     objSFD = new SaveFileDialog()
    {
        // DefaultExt = "csv",
        Filter = "Powerpoint Presentation (*.pptx)|*.pptx | All files (*.*)|*.*",
        FilterIndex = 1,

    };

    if ( objSFD.ShowDialog()==true)
    {
// Here Configuration is a class in the Service. Please look at service for more information
//about this class
        List<ServiceReference.Configuration>
        obj = new List<ServiceReference.Configuration>();

//Data can be anything which needs to go into ppt as table
        foreach (var config in Data)
        {
            obj.Add(new ServiceReference.Configuration()
            {
                Value = Data.Value,
                Name = Data.Name,
            });
        }

        proxy.CreateTableInLastSlideAsync
        (new System.Collections.ObjectModel.ObservableCollection<Configuration>(obj));
        proxy.CreateTableInLastSlideCompleted +=
        new EventHandler<CreateTableInLastSlideCompletedEventArgs>
            (proxy_CreateTableInLastSlideCompleted);
    }
}

void proxy_CreateTableInLastSlideCompleted
    (object sender, CreateTableInLastSlideCompletedEventArgs e)
{
    if (e.Result == null)
        return;

    using (System.IO.Stream stream = objSFD.OpenFile())
    {
        stream.Write(e.Result, 0, e.Result.Length);

    }
}

You will be able to see the output as below:

Powerpoint with OpenXML image

Powerpoint with OpenXML

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)