简体   繁体   中英

OpenXML refresh connectors on a PowerPoint Slide automatically

I have a simple scenario where I programmatically create a presentation with a slide using OpenXML SDK 2.5 and c#. The slide has 2 shapes on it as well as a connector that connects these 2 shapes.

When I open the presentation in PowerPoint both shapes and the connector shown, but the connector is not positioned properly between the shapes. When I drag one of the shapes on the slide, PowerPoint immediately refreshes the connector and puts it into the correct position.

My question: is it possible to create an openxml PowerPoint slide that automatically refreshes the connector positions when the file is opened?

Thank you

The solution I came up with for this problem may seem rather hack-ish, but as far as I can tell there isn't a better way. The problem is that PowerPoint controls connector placement internally and doesn't expose any methods to refresh them. In testing, I was amazed to discover that PowerPoint will dynamically change the connector type during the refresh if necessary.

In order to get the refresh to happen, I had to write a VBA macro in a .pptm file and call it from my C# code. I added a module and put the function there so it wouldn't be associated with a particular slide.

This code moves each shape on a slide in order to cause the connector refresh to fire. It looks for shapes inside of groups too. It is filtering on triangle and diamond shapes.

I avoided using ActivePresentation in the code because I want to hide PowerPoint while the macro runs.

Public Sub FixConnectors()
    Dim mySlide As Slide
    Dim shps As Shapes
    Dim shp As Shape
    Dim subshp As Shape

    Set mySlide = Application.Presentations(1).Slides(1)
    Set shps = mySlide.Shapes

    For Each shp In shps
        If shp.AutoShapeType = msoShapeIsoscelesTriangle Or shp.AutoshapeType = msoShapeDiamond Then
            shp.Left = shp.Left + 0.01 - 0.01
        End If
        If shp.Type = mso.Group Then
            For Each subshp In shp.GroupItems
                If subshp.AutoShapeType = msoShapeIsoscelesTriangle Or subshp.AutoshapeType = msoShapeDiamond Then
                    subshp.Left = subshp.Left + 0.01 - 0.01
                End If
             Next subshp
        End If
    Next shp

    Application.Presentations(1).Save
End Sub

Next comes the C# code to run the macro using PowerPoint Interop. Closing and reopening the file as a Windows process allows the garbage collector to clean up any handles that Interop has. In testing, the finalizers could take several seconds to run so the GC calls happen after reopening the file so the application doesn't appear to hang.

using System;
using System.Diagnostics;
using OC = Microsoft.Office.Core;
using PP = Microsoft.Office.Interop.PowerPoint;

string filePath = "C:/Temp/";
string fileName = "Template.pptm";

// Open PowerPoint in hidden mode, run the macro, and shut PowerPoint down
var pptApp = new PP.Application();
PP.Presentation presentation = pptApp.Presentations.Open(filePath + fileName, OC.MsoTriState.msoFalse, OC.MsoTriState.msoFalse, OC.MsoTriState.msoFalse);
pptApp.Run(filename + "!.FixConnectors");
presentation.Close();
presentation = null;
pptApp.Quit();
pptApp = null;

// Reopen the file through Windows
Process.Start(filePath + fileName);

// Clear all references to PowerPoint
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();

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