简体   繁体   中英

VSTO OpenXml C# - Edit PowerPoint on Runtime

I've read a lot about editing pptx files with OpenXml like

PresentationDocument presentationDocument = PresentationDocument.Open("C:\\Users\\beggers\\Desktop\\Test.pptx", true)

But how can I modify the XML data of my slides/presentation on runtime? Specialy when I run a new presentation witch is not saved.

I am working on a C# VSTO Add-in and I want to modify my slide/xml in a way, which is not supportet by Microsoft.Office.Interop.

Unfortunately, Microsoft Word is the only Office application that offers an Interop API for reading and even writing Open XML markup, in that case of a given Range object (which can also be the Range representing the whole main document part). Neither Excel nor PowerPoint provides that capability.

Even Microsoft Word does not give you the full markup, though, meaning you can't read or change every aspect of the opened document by reading or making changes to the Open XML markup. Thus, depending on what you would like to do with your document, you will have to close and reopen even Word documents to access and process the full Open XML markup.

A sub-optimal yet functional way to do this is round trip using the clipboard. Slide(s) copied to the clipboard are actually packaged up as ppt data (which is just a zip). And you have control over the clipboard and inserting etc slides. So basically:

  1. Programmatically select and copy the content you want to edit to the clipboard using PP APIs.
  2. Read "PowerPoint 14.0 Slides Package" part of clipboard data into memory stream.
  3. Pass/edit memory stream with Open XML.
  4. Copy memory stream back to clipboard.
  5. paste back into PP as needed.

Here's an example of steps 2-3 working using this Open XML example as a base that write all text in the first slide in the clipboard to the console:

using System;
using System.IO; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using P = DocumentFormat.OpenXml.Presentation;
using D = DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;

namespace PPClipboardTest
{    
    class Program
    {
        public static string format = "PowerPoint 14.0 Slides Package";


        // Get all the text in a slide.
        public static string[] GetAllTextInSlide(string presentationFile, int slideIndex)
        {
            // Open the presentation as read-only.
            using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
            {
                // Pass the presentation and the slide index
                // to the next GetAllTextInSlide method, and
                // then return the array of strings it returns. 
                return GetAllTextInSlide(presentationDocument, slideIndex);
            }
        }

        public static string[] GetAllTextInSlide(PresentationDocument presentationDocument, int slideIndex)
        {
            // Verify that the presentation document exists.
            if (presentationDocument == null)
            {
                throw new ArgumentNullException("presentationDocument");
            }

            // Verify that the slide index is not out of range.
            if (slideIndex < 0)
            {
                throw new ArgumentOutOfRangeException("slideIndex");
            }

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

            // Verify that the presentation part and presentation exist.
            if (presentationPart != null && presentationPart.Presentation != null)
            {
                // Get the Presentation object from the presentation part.
                Presentation presentation = presentationPart.Presentation;

                // Verify that the slide ID list exists.
                if (presentation.SlideIdList != null)
                {
                    // Get the collection of slide IDs from the slide ID list.
                    DocumentFormat.OpenXml.OpenXmlElementList slideIds =
                        presentation.SlideIdList.ChildElements;

                    // If the slide ID is in range...
                    if (slideIndex < slideIds.Count)
                    {
                        // Get the relationship ID of the slide.
                        string slidePartRelationshipId = (slideIds[slideIndex] as SlideId).RelationshipId;

                        // Get the specified slide part from the relationship ID.
                        SlidePart slidePart =
                            (SlidePart)presentationPart.GetPartById(slidePartRelationshipId);

                        // Pass the slide part to the next method, and
                        // then return the array of strings that method
                        // returns to the previous method.
                        return GetAllTextInSlide(slidePart);
                    }
                }
            }

            // Else, return null.
            return null;
        }

        public static string[] GetAllTextInSlide(SlidePart slidePart)
        {
            // Verify that the slide part exists.
            if (slidePart == null)
            {
                throw new ArgumentNullException("slidePart");
            }

            // Create a new linked list of strings.
            LinkedList<string> texts = new LinkedList<string>();

            // If the slide exists...
            if (slidePart.Slide != null)
            {
                // Iterate through all the paragraphs in the slide.
                foreach (DocumentFormat.OpenXml.Drawing.Paragraph paragraph in
                    slidePart.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
                {
                    // Create a new string builder.                    
                    StringBuilder paragraphText = new StringBuilder();

                    // Iterate through the lines of the paragraph.
                    foreach (DocumentFormat.OpenXml.Drawing.Text text in
                        paragraph.Descendants<DocumentFormat.OpenXml.Drawing.Text>())
                    {
                        // Append each line to the previous lines.
                        paragraphText.Append(text.Text);
                    }

                    if (paragraphText.Length > 0)
                    {
                        // Add each paragraph to the linked list.
                        texts.AddLast(paragraphText.ToString());
                    }
                }
            }

            if (texts.Count > 0)
            {
                // Return an array of strings.
                return texts.ToArray();
            }
            else
            {
                return null;
            }
        }



        [STAThread]
        static void Main(string[] args)
        {
            IDataObject iData = new DataObject();

            iData = Clipboard.GetDataObject();
            string[] formats = iData.GetFormats();

            foreach(string f in formats)
            {
                if(f == format)
                {
                    MemoryStream ms = iData.GetData(format) as MemoryStream;

                    using (PresentationDocument pres = PresentationDocument.Open(ms, true))
                    {
                        string[] allText = GetAllTextInSlide(pres, 0);
                        Console.Write("Text in first slide copied to clipboard:\n");
                        foreach (string txt in allText)
                        {
                            
                            Console.Write(txt + "\n");
                        }
                    }

                    /*
                    // Write to file
                    using (FileStream file = new FileStream("file.ppt", FileMode.Create, System.IO.FileAccess.Write)) // Bin chunk from clipboard is just a zip file
                    {
                        byte[] bytes = new byte[ms.Length];
                        ms.Read(bytes, 0, (int)ms.Length);
                        file.Write(bytes, 0, bytes.Length);
                        ms.Close();
                    }
                    */


                    break;
                }
            }            
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM