Hello everybody,
I'm into troubles that nearly drive my crazy. I would like to achieve connections between shapes by using GlueTo which ends in a COMException. Before I get close to the error I want to explain what happens before:
1. Load 500 shapes from the stencil into an shape array: shapes[index] = stencil.Masters[@"SHAPENAME"].Shapes[1];
Everything works fine here.
2. Load 499 connector shapes from the into the shape array: shapes[index] = stencil.Masters[@"CONNECTORNAME"].Shapes[1]
Still everthing's fine.
3. Make some property changes to the 2-D-shapes and drop all 999 shapes: page.Drop(shapes[index], X-VALUE, Y-VALUE);
4. Glue the connector's BeginX to a shape's PinX: Cell conBeginX = shapes[index].CellsSRC[(short) VisSectionIndices.visSectionObject, (short) VisRowIndices.visRowXForm1D, (short) VisCellIndices.vis1DBeginX];
conBeginX.GlueTo(fromShape.CellsSRC[(short) VisSectionIndices.visSectionObject, (short) VisRowIndices.visRowXFormOut, (short) VisCellIndices.visXFormPinX]);
I get the COMException at the last line with the message: "Inappropriate target object for this action"
I also used AutoConnect which failed at the same level but worked while I dropped the shapes directly out of the master instead of dropping them out of the shape array (could there be the problem?).
I'll be glad for every kind of advice.
Have a nice weekend.
Charly.
You can't glue to the PinX cell. You normally glue to a ConnectionPoint. I guess you wan't to achieve dynamic glueing? That is done in a different way, that I (sorry) can't remember at the momnet, but perhaps you can look arround a bit or one of the other guys, knows how to.
hth Jumpy
Hi Jumpy,
thanks for your advice. I also tried to glue the connector's BeginX to a other shape's connection point which failed too because of an "Inappropriate target object for this action". Even the shape.AutoConnect function delivers the same error. My mistake seems to be somewhere else. Maybe it is not possible to glue shapes that are not directly derived from a master?
charly.
This works for me. I included a couple of functions to create some 'standard' connection points as examples.
Dim strNodeAConn As String
Dim strNodeBConn As String
' strPortA and strPortB are the connection point names (ex. center, left, right, top, bottom)
strNodeAConn = "Connections." & strPortA
strNodeBConn = "Connections." & strPortB
' strNodeA and strNodeB are obviously the shapenames
Set objNodeA = vsoShapes.Item(strNodeA)
Set objNodeB = vsoShapes.Item(strNodeB)
' objCable is the dynamic connector
Dim objBeginX As Visio.Cell
Dim objEndX As Visio.Cell
Set objBeginX = objCable.CellsSRC( _
visSectionObject, visRowXForm1D, vis1DBeginX)
objBeginX.GlueTo objNodeA.Cells(strNodeAConn)
Set objEndX = objCable.CellsSRC( _
visSectionObject, visRowXForm1D, vis1DEndX)
objEndX.GlueTo objNodeB.Cells(strNodeBConn)
DoEvents
'*********************************************************************
'*********************************************************************
'
' Standard Connections (left, right, top, bottom, center)
'
'*********************************************************************
'*********************************************************************
Public Sub AddStandardConnections _
(ByVal visShape As Visio.Shape)
Dim visSection As Integer
Dim blnResult As Boolean
visSection = visSectionConnectionPts
' check to make sure the section exists first
If visShape.SectionExists(visSection, False) = False Then
visShape.AddSection (visSection)
End If
' since we have connections on all four sides we probably dont need a middle
blnResult = funcAddConnectionPointToShape(visShape, "center", "center", "center", _
2, "Width * 0.5", "Height * 0.5", 0, False)
blnResult = AddConnectionPointToShape(visShape, "left", "left", "left", _
2, "0", "Height * 0.5", "0", False)
blnResult = AddConnectionPointToShape(visShape, "right", "right", "right", _
2, "Width", "Height * 0.5", "0", False)
blnResult = AddConnectionPointToShape(visShape, "top", "top", "top", _
2, "Width * 0.5", "Height", "0", False)
blnResult = AddConnectionPointToShape(visShape, "bottom", "bottom", "bottom", _
2, "Width * 0.5", "0", "0", False)
End Sub
'*********************************************************************
'*********************************************************************
'
' Connection Points
'
'*********************************************************************
'*********************************************************************
Public Function AddConnectionPointToShape _
(ByVal vsoShape As Visio.Shape, _
ByVal strLocalRowName As String, _
ByVal strRowNameU As String, _
ByVal strLabelName As String, _
ByVal strConnectType As String, _
ByVal strX As String, _
ByVal strY As String, _
Optional ByVal strDirX As String = "", _
Optional ByVal strDirY As String = "", _
Optional ByVal blnAutoGen As Boolean = False) _
As Boolean
Dim vsoCell As Visio.Cell
Dim intRowIndex As Integer
If vsoShape.SectionExists(visSectionConnectionPts, False) = False Then
vsoShape.AddSection (visSectionConnectionPts)
End If
intRowIndex = vsoShape.AddNamedRow(visSectionConnectionPts, _
strLocalRowName, _
Visio.VisRowIndices.visRowConnectionPts)
' Column 0: X
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visX)
vsoCell.Formula = strX
If (strLocalRowName <> strRowNameU And _
Len(strRowNameU) > 0) Then
vsoCell.RowNameU = strRowNameU
End If
' Column 1: Y
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visY)
vsoCell.Formula = strY
' Column 2: direction x
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visCnnctDirX)
vsoCell.Formula = strDirX
' Column 3: direction y
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visCnnctDirY)
vsoCell.Formula = strDirY
' Column 4: type
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visCnnctType)
vsoCell.Formula = strConnectType
' Column 5: autogen
Set vsoCell = vsoShape.CellsSRC(visSectionConnectionPts, _
visRowConnectionPts + intRowIndex, visCnnctAutoGen)
vsoCell.ResultIU = blnAutoGen
AddConnectionPointToShape = True
End Function
@alelund:
Where do you get the vsoShapes from?
sorry (my fault for trying to just grab what was relevant).
dim vsoShapes as visio.shapes
set vsoShapes = application.activepage.shapes
al
Hi aledlund,
thank you for your explanation. I think my question wasn't as precise as it had to be.
There is no problem when I drop the shapes calling page.Drop(stencil.Masters["MASTERNAME"], X, Y)
In this case GlueTo works without any error. But when I add the shapes to an array shapes[index] = stencil.Masters[@"SHAPENAME"].Shapes[1];
and drop them later page.Drop(shapes[index], X-VALUE, Y-VALUE);
GlueTo fails as well as shape.AutoConnect.
If it's always on the last shape in the array, I start to suspect an indexing issue (start at 0 vs start at 1, or vicea-versa).
al
Unfortunately it's already the first item of the which connection does not work. But these one based indices of Visio elements are nevertheless very awful.
The dropping of the Array of shapes is still OK I guess?
So could you perhaps post a little more code. Everything arround the part, where you attempt the glueing (perhaps including the loop(s)).
Ok. So here is (almost) the whole code:
ActiveDiagramControl: the Visio OCX
if (ActiveDiagramControl.Instance != null)
{
Application visioApplication = ActiveDiagramControl.Instance.Document.Application;
Page page = visioApplication.ActivePage;
Document stencil = visioApplication.Documents[2];
Document drawing = visioApplication.ActiveDocument;
Shape[] shapes = new Shape[graphicElements.Count];
int index = 0;
// Create the shapes
foreach(GraphicElement element in graphicElements)
{
switch (element.ElementType)
{
case ElementType.Function:
{
shapes[index] = stencil.Masters["Function"].Shapes[1];
break;
}
case ElementType.Connector:
{
shapes[index] = stencil.Masters["Connector"].Shapes[1];
break;
}
}
index++;
}
visioApplication.ShowChanges = false;
index = 0;
bool isFunctionDropped = false;
bool isConnectorDropped = false;
string lastFunctionName = string.Empty;
string lastConnectorName = string.Empty;
foreach(GraphicElement element in graphicElements)
{
if (shape.OneD == 0)
{
shapes[index].Text = index.ToString();
shapes[index].Cells["Width"].Formula = "30mm";
shapes[index].Cells["Height"].Formula = "20mm";
shapes[index].Cells["LineWeight"].Formula = "1mm";
shapes[index].Cells["LineColor"].Formula = "1";
shapes[index].Cells["Rounding"].Formula = "0.3mm";
shapes[index].Cells["FillBkgnd"].Formula = "2";
shapes[index].Cells["FillForegndTrans"].Formula = "90%";
shapes[index].Cells["FillBkgndTrans"].Formula = "0%";
shapes[index].Cells["FillForegnd"].Formula = "3";
lastFunctionName = shape.Name;
isFunctionDropped = true;
if (isConnectorDropped)
{
Cell conEndX = page.Shapes[lastConnectorName].CellsSRC[VisEnum.VIS_SECTION_OBJECT, VisEnum.VIS_ROWX_FORM_1_D, VisEnum.VIS_1_D_END_X];
conEndX.GlueTo(shape.Cells["Connections.W"]);
}
}
page.Drop(shapes[index], element.X, element.Y);
// Glue
if (shape.OneD == -1 && index > 0 && isFunctionDropped)
{
// Connector's begin to
Shape fromShape = page.Shapes[lastFunctionName];
Cell conBeginX = shapes[index].CellsSRC[VisEnum.VIS_SECTION_OBJECT, VisEnum.VIS_ROWX_FORM_1_D, VisEnum.VIS_1_D_BEGIN_X];
conBeginX.GlueTo(fromShape.Cells["Connections.E"]);
lastConnectorName = shape.Name;
isConnectorDropped = true;
}
index++;
}
I made minor modifications to my code so I hope it is consistent yet.
In the second ForEach-Loop, the first time the variable shape is not defined or is not assigned.
Later on, when you drop the shape:
page.Drop(shapes[index], element.X, element.Y);
you don't retain a reference to that shape.
With sth. like:
Shape Newshape = page.Drop(shapes[index], element.X, element.Y);
you can maybe avoid the complications with remembering the last shape via it's name:
Shape fromShape = page.Shapes[lastFunctionName];
--------------
If the shapes are alternating, e.g. function connector function connector function ...
you could try a different aproach by simply use of two variables, oldshape, newshape:
If newshape is a function and oldshape is empty, do nothing because it's the first shape (ecxept the Alterations of some properties)
If newshape is a function and oldshape is/has to be a connecor then glue the end of the connector to newshape
(and make the Alterations of some properties)
If newshape is a connector and oldshape is/has to be a function then glue begin of the connector to oldshape
Finally set Oldshape=newshape
Loop
Hi Jumpy,
thank you very much for this advice. I tried it with only one connection an it worked as demanded. Now I am going try it with thousand shapes but I got no doubts it will work too.