Container Copy Styling Issues (continued)

Started here:

After the 25.11 update I’m still seeing some issues with styling of copied containers.
Issues:

  1. The first container copy is quite a bit wider than the original or the other copies.
  2. The style still doesn’t seem to have completely applied. If you select a container, go to container properties in the toolbar, and click the (already) selected container style, it “finishes” applying the style and it looks correct.
  3. With the original container, if you click the container style, it doesn’t do anything. With the copies, each time you click the style it expands the container vertically and messes up the contained shapes. Not sure why this is (and this is a very minor issue…I just noticed it and thought I’d bring it up).
  4. The containerproperties object still isn’t exposed anywhere I can find in the API. If we can get it to work without specifically referencing that object I guess it’s not a big deal. On the other hand it would make sense to me that there might be instances where I would want to change which container style a container had, and I don’t see how that would be possible without referencing the container specifically (as opposed to the shape).

Here are the script, the source file and a sample output file.

containerstyle_poc.zip (137.6 KB)

I have made the following changes to the POC code:

  1. I stopped removing the placeholder page (so that comparisons are easier)
  2. I added a .RefreshData() and .Move(0.0,0.0) to the loop.

Here’s the code:

function Find-VisioShape {
    [CmdletBinding()]
    param($page,
        [string]$Key,
        [string]$Value
    )

    foreach ($item in $page.Shapes) {
        $prop = $item.props.GetProp($Key)
        if ($prop -and ($prop.value.val -eq $Value)) {
            return $item
        }
    }
}

add-type -path  'C:\Program Files (x86)\Aspose\Aspose.Diagram for .NET\bin\net4.0\Aspose.Diagram.dll'
$Template = 'c:\temp\containerstyle_poc.vsdx'
$diagramFile =  'c:\temp\containerstyle_poc_output.vsdx'

Copy-Item $template $diagramFile
 
$doc = New-Object Aspose.Diagram.Diagram -ArgumentList $diagramFile

#get source container and shape from first page
$sourcepage = $doc.pages[0]
$sourceContainer = Find-VisioShape -page $sourcepage -key Container -value "PLACEHOLDER"
$sourceShape = Find-VisioShape -page $sourcepage -key Shape -value "PLACEHOLDER"
   
#get page for output of data
$page = $doc.pages[1]

$data = @'
Column,Value
Column1,Value1
Column1,Value2
Column2,Value3
Column2,Value4
Column2,Value5
Column3,Value6
'@ | ConvertFrom-Csv 
$columns = $data | Group-Object -Property Column


$objectNumber = 1000
$pos = 1

foreach ($column in $columns) {
    Write-Host "Working with column $($column.Name)"
        
    $container = New-Object Aspose.Diagram.Shape
    $container.Copy($sourceContainer)
    $null = $doc.Addshape($container, $container.master.name, ($doc.pages.id).indexof($page.id))
    $container.xform.pinx.value = $pos
    $container.Name = "Column_$ObjectNumber"
    $container.Text.Value.Clear()
    $null = $container.Text.Value.add((New-Object aspose.diagram.txt $column.Name))
    $objectNumber++
    $products = $column.group | Sort-Object Value
    $lastY = -1
    $Container.xform.pinpos = 1
    $container.xform.height.value += ($sourceshape.xform.height.value * $products.count)
    foreach ($product in ($products | Sort-Object Value)) {
           
        $shape = New-Object Aspose.Diagram.Shape
        $shape.Copy($sourceshape)
            
        ($shape.Text.Value | Where-Object { $_.Text } | Select-Object -First 1).text = $product.Value
        if ($lastY -eq -1) {
            $lastY = $shape.xform.piny.value
        } else {
            $shape.MoveTo($pos, $lastY - $shape.xform.height.value)
            $lastY = $lasty - $shape.xform.height.value
        }
            
        $shape.xform.pinx.value = $pos
        $null = $doc.Addshape($shape, $shape.master.name, ($doc.pages.id).indexof($page.id))
        $shape.Name = "Object.$ObjectNumber"
        #write-host "Added shapeID ($($shape.id)) - ($($shape.name))"
        $objectNumber++
    }
    $pos += $container.xform.width.value + 0.5
    $container.RefreshData()
    $container.Move(0.0,0.0)

}
   
#$doc.pages.Remove($doc.pages[0]) 
$doc.Save($diagramFile, [Aspose.Diagram.SaveFileFormat]::vsdx)
   
Invoke-Item $diagramfile

@MikeShepard1

Summary
You can copy shapes (including containers) with the Aspose.Diagram SDK using Shape.Copy() (or Clone() in some language bindings) and then add the copy to a page with Diagram.AddShape(). After copying, call Shape.RefreshData() to make sure the shape’s data (including any style information that is stored in the shape’s XML) is re‑loaded before you modify its geometry.

Why it happens

Symptom What the SDK does (according to the documentation)
The copied container looks different (e.g., wider) Shape.Copy() creates a new shape that contains the same XML as the source. If the source shape’s width is defined in its master or in a hidden section, the copy will retain that value until you explicitly change the XForm.Width property.
Style appears only after you click the shape in Visio The SDK does not automatically re‑evaluate style rules after a copy. Calling RefreshData() forces the SDK to re‑read the shape’s XML, which includes style references.
No ContainerProperties class is visible The documentation lists generic shape members (e.g., XForm, Line, Fill, Text, Style). Container‑specific settings are stored in hidden XML sections that are not exposed as a separate class.

What to do next

  1. Copy the shape
$container = New-Object Aspose.Diagram.Shape
$container.Copy($sourceContainer) # copies the placeholder container
$doc.AddShape($container, $container.Master.Name, $page.Index)
  1. Refresh the shape data before changing geometry or style:
$container.RefreshData()
  1. Set the width (or any other geometry) explicitly if you need it to match the original:
$container.XForm.Width.Value = $sourceContainer.XForm.Width.Value
  1. Apply the style (if you want to be sure the same style is used):
$container.Style = $sourceContainer.Style
$container.RefreshData()
  1. Repeat the same steps for inner shapes (copy, add, refresh, then adjust position/size).
  2. Container‑specific flags (e.g., AutoSize) are stored in hidden XML sections. The SDK does not expose a dedicated ContainerProperties object, so you would need to manipulate the underlying XML directly if you must change those flags.

Result – By copying the shape, calling RefreshData(), and then explicitly setting geometry and style, the copied containers should look the same as the original and the style will be applied without needing to click the shape in Visio. For any container‑only settings that are not exposed through the SDK, you will have to edit the shape’s XML manually.

Note: The above steps are derived from the Aspose.Diagram documentation that describes copying shapes and using RefreshData(). Specific behaviour of container width or style re‑application after a click in Visio is not covered by the documentation, so the suggested approach is based on the general shape‑copy workflow provided by the SDK.

:warning: I could not fully verify this explanation against the retrieved sources. Please double-check the behaviour in your environment and confirm the exact SDK/version.

SDK version unclear — refer to the official release notes before applying this guidance.

@MikeShepard1
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): DIAGRAMNET-53844

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.