In my PowerPoint AddIn I want to access shapes on the slides. The shapes are placeholders defined in custom layouts in the slidemaster.
When I add a slide based on the custom layout, the shapes just get named "placeholder 1", "placeholder 2", ...
Is there a way to get the placeholder by the name given in the master?
Currently I am searching shapes with this code:
public static Shape GetShape(string stringToSearch, Shapes shapes) {
foreach (Shape shape in shapes) {
if (shape.Name == stringToSearch) {
return shape;
}
// Search Groups
if (shape.Type == MsoShapeType.msoGroup) {
foreach (Shape childshape in shape.GroupItems) {
if (childshape.Name == stringToSearch) {
return childshape;
}
}
}
}
throw new KeyNotFoundException("No Shape found");
}
Update: Maybe to make it more clear, this is the structure of the PowerPoint-Presentation.
Master with Names defined for placeholders:
Presentation where names defined in master are lost:
Problem: How to get element in presentation, by name defined in master?
Well.. here is Steve's "Ugly!" solution.
For my project I neither have nor want control over creation of shapes so I cannot "tag" them. That is why I have a custom placeholder name to identify them, So the names of shapes will indeed be [PlaceholderType] ##.
The steps:
Note: I don't use shape groups. this technique will get a lot more complicated if you do and you need to check inside groups.
This is the function that does that and returns a mastershapename - shapename mapping.
private Dictionary<string, string> GetShapeMasters(Powerpoint.Slide s)
{
Dictionary<string, string> shapeMasters = new Dictionary<string, string>();
List<ShapeLocation> shapeLocations = new List<ShapeLocation>();
//store locations
foreach (Powerpoint.Shape sh in s.Shapes)
{
shapeLocations.Add(new ShapeLocation()
{
Name = sh.Name,
Location = new System.Drawing.RectangleF(sh.Left, sh.Top, sh.Width, sh.Height)
});
}
//have powerpoint reset the slide
//ISSUE: this changes the names of placeholders without content.
s.CustomLayout = s.CustomLayout;
//compare slide and master
foreach (Powerpoint.Shape sh in s.Shapes)
{
foreach (Powerpoint.Shape msh in s.CustomLayout.Shapes)
{
if (IsShapeMaster(sh, msh))
{
shapeMasters[msh.Name] = sh.Name;
}
}
}
//restore locations
//TODO: might be replaced by undo
foreach (var shm in shapeLocations)
{
Powerpoint.Shape sh = null;
try
{
sh = s.Shapes[shm.Name];
}
catch
{
//Fails for renamed placeholder shapes.
//Have yet to find a decent way to check if a shape name exists.
}
//placeholders do not need to be restored anyway.
if (sh != null)
{
sh.Left = shm.Location.Left;
sh.Top = shm.Location.Top;
sh.Width = shm.Location.Width;
sh.Height = shm.Location.Height;
}
}
return shapeMasters;
}
With this you can do
Dictionary<string, string> shapeMasters = GetShapeMasters(theSlide);
if(shapeMasters.ContainsKey(stringToSearch))
Powerpoint.Shape KnownShape = theSlide[shapeMasters[stringToSearch]];
And here is the comparison function that takes two shapes and checks if they are "equal". Could be extended to make it more precise.
private bool IsShapeMaster(Powerpoint.Shape sh, Powerpoint.Shape msh)
{
return
sh.Left == msh.Left
&& sh.Top == msh.Top
&& sh.Width == msh.Width
&& sh.Height == msh.Height
&& sh.Type == msh.Type
&& sh.PlaceholderFormat.Type == msh.PlaceholderFormat.Type;
}
Little class that stores original shape location
class ShapeLocation
{
public string Name;
public System.Drawing.RectangleF Location;
}
I'm open to suggestions because I don't like this, either. Only there seems to be no other way to link shapes and placeholders together. There really isn't some shape.MasterShape
we are missing, is there?
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.