简体   繁体   English

PowerPoint幻灯片上的OpenXML自动刷新连接器

[英]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#. 我有一个简单的场景,其中我使用OpenXML SDK 2.5和c#以编程方式创建一个带有幻灯片的演示文稿。 The slide has 2 shapes on it as well as a connector that connects these 2 shapes. 幻灯片上有2种形状,还有一个连接这2种形状的连接器。

When I open the presentation in PowerPoint both shapes and the connector shown, but the connector is not positioned properly between the shapes. 当我在PowerPoint中打开演示文稿时,会同时显示两个形状和连接器,但是连接器在两个形状之间的位置不正确。 When I drag one of the shapes on the slide, PowerPoint immediately refreshes the connector and puts it into the correct position. 当我在幻灯片上拖动一个形状时,PowerPoint立即刷新连接器并将其放置在正确的位置。

My question: is it possible to create an openxml PowerPoint slide that automatically refreshes the connector positions when the file is opened? 我的问题:是否可以创建一个openxml PowerPoint幻灯片,该幻灯片在打开文件时自动刷新连接器位置?

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. 问题是PowerPoint内部控制了连接器的放置,并且没有公开任何刷新它们的方法。 In testing, I was amazed to discover that PowerPoint will dynamically change the connector type during the refresh if necessary. 在测试中,我惊讶地发现PowerPoint会在刷新期间根据需要动态更改连接器类型。

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. 为了使刷新发生,我不得不在.pptm文件中编写一个VBA宏,然后从我的C#代码中调用它。 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. 我避免在代码中使用ActivePresentation,因为我想在宏运行时隐藏PowerPoint。

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. 接下来是C#代码,以使用PowerPoint Interop运行宏。 Closing and reopening the file as a Windows process allows the garbage collector to clean up any handles that Interop has. 作为Windows进程关闭并重新打开文件,垃圾回收器可以清理Interop拥有的所有句柄。 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. 在测试中,终结器可能需要花费几秒钟来运行,因此GC调用在重新打开文件后发生,因此应用程序似乎没有挂起。

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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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