Modifying the code which loops through names in an assembly

My code is posted after my question.

The array FLART(3) has the names of components within our database. Array values (0), (1), (2) are single components and value (3) is an assembly with sub assemblies in it. When I run the code with the array in this order it works fine(I was simply testing if I could return the top level name of each item). If I run the code with value (3) swapped with any other value it fails because it's opening an assembly and then trying to open a single component afterwards. I'm not sure how to get around this issue.

My end goal for this test code was to return the name of every part I open. If it's an assembly return the name of the assembly, sub assemblies, and components and if it's a single part return the name of the single part.

The final part I'm having trouble with is how to Save-As WorkPart New Item within CPLM.

Ultimately I want to take all of the names I gathered and check them against a two dimensional array where the first dimension is the current name of components I may be opening and the second dimension is a new name I want to save them as.

Creating the two dimensional array and checking against it has been figured out it's just navigating OpenNX that has me confused.

'Journal to recursively walk through the assembly structure
' will run on assemblies or piece parts
' will step through all components of the displayed part
'NX 7.5, native
'NXJournaling.com February 24, 2012

Option Strict Off

Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies

Module NXJournal

Public theSession As Session = Session.GetSession()
Public ufs As UFSession = UFSession.GetUFSession()
Public lw As ListingWindow = theSession.ListingWindow

Sub Main()
Dim workPart As NXOpen.Part = theSession.Parts.Work
Dim dispPart as NXOpen.Part = theSession.Parts.Display
Dim fileNameNoExt As String
Dim basePart1 As NXOpen.BasePart = Nothing
Dim partLoadStatus1 As NXOpen.PartLoadStatus = Nothing

Dim PartNames(0) As String
Dim FLART(3) as string
Dim ArrayIndex as integer = 0
Dim i as integer
Dim theUISession As UI = UI.GetUI
Dim c As ComponentAssembly = dispPart.ComponentAssembly

FLART(0) = "Part1"
FLART(1) = "Part2"
FLART(2) = "Part3"
FLART(3) = "Assembly1"

lw.Open

for i = 0 to 3

'TRIES TO OPEN THE PART SPECIFIED IN THE ARRAY
basePart1 = theSession.Parts.OpenActiveDisplay("@DB/" & FLART(i) & "/" & 1, NXOpen.DisplayPartOption.AllowAdditional, partLoadStatus1)

lw.writeline("ForLoop: " & i)

if not IsNothing(c.RootComponent) then

if ArrayIndex = 0 then
lw.writeline("Is first part and is an assembly")
fileNameNoExt = c.RootComponent.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
PartNames(ArrayIndex) = FileNameNoExt
lw.WriteLine("Assembly: " & PartNames(ArrayIndex))
ArrayIndex = ArrayIndex + 1
else
lw.writeline("Not first part and is an assembly")
Redim Preserve PartNames(ArrayIndex)
fileNameNoExt = c.RootComponent.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
PartNames(ArrayIndex) = fileNameNoExt
lw.WriteLine("Assembly: " & PartNames(ArrayIndex))
ArrayIndex = ArrayIndex + 1
end if

'*** insert code to process 'root component' (assembly file)
'lw.WriteLine(" + Active Arrangement: " & c.ActiveArrangement.Name)
'*** end of code to process root component
'ReportComponentChildren(c.RootComponent, 0)
else
'*** insert code to process piece part

lw.writeline("Piece Part")
if ArrayIndex = 0 then

lw.writeline("First Part is a Piece Part")
'UPDATES THE WORK VIEW TO THE NEW PART THAT WAS JUST OPENED IN ORDER TO MAKE THE DISPLAYED PART THE WORK PART
'dispPart.ModelingViews.WorkView.UpdateDisplay()
'MAKES THE DISPLAYED PART THE WORK PART
dispPart = theSession.Parts.Display
fileNameNoExt = dispPart.FullPath
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
lw.writeline("FileNameNoExt: " & fileNameNoExt) 'WRITES THE NAME OF THE OBJECT TO THE LISTING WINDOW
PartNames(ArrayIndex) = fileNameNoExt
ArrayIndex = ArrayIndex + 1

else

lw.writeline("Not First part and is Piece Part")
'UPDATES THE WORK VIEW TO THE NEW PART THAT WAS JUST OPENED IN ORDER TO MAKE THE DISPLAYED PART THE WORK PART
'dispPart.ModelingViews.WorkView.UpdateDisplay()
'MAKES THE DISPLAYED PART THE WORK PART
dispPart = theSession.Parts.Display
Redim Preserve PartNames(ArrayIndex)
fileNameNoExt = dispPart.FullPath
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
lw.writeline("FileNameNoExt: " & fileNameNoExt) 'WRITES THE NAME OF THE OBJECT TO THE LISTING WINDOW
PartNames(ArrayIndex) = fileNameNoExt
ArrayIndex = ArrayIndex + 1

end if

lw.WriteLine(PartNames(UBound(PartNames)))

end if

theSession.CleanUpFacetedFacesAndEdges()
theSession.Parts.Display.Close(BasePart.CloseWholeTree.True, BasePart.CloseModified.UseResponses, Nothing)

next

lw.Close

End Sub

'**********************************************************
Sub reportComponentChildren( ByVal comp As Component, _
ByVal indent As Integer)

For Each child As Component In comp.GetChildren()
'*** insert code to process component or subassembly
lw.WriteLine(New String(" ", indent * 2) & child.DisplayName())
'*** end of code to process component or subassembly
if child.GetChildren.Length <> 0 then
'*** this is a subassembly, add code specific to subassemblies
lw.WriteLine(New String(" ", indent * 2) & _
"* subassembly with " & _
child.GetChildren.Length & " components")
lw.WriteLine(New String(" ", indent * 2) & _
" + Active Arrangement: " & _
child.OwningPart.ComponentAssembly.ActiveArrangement.Name)
'*** end of code to process subassembly
else
'this component has no children (it is a leaf node)
'add any code specific to bottom level components
end if
reportComponentChildren(child, indent + 1)
Next
End Sub
'**********************************************************
Public Function GetUnloadOption(ByVal dummy As String) As Integer
Return Session.LibraryUnloadOption.Immediately
End Function
'**********************************************************

End Module

In interactive NX, if you try to open a part that is already open, you will get a message that the part is already open and an option to reopen the part, make it the display part, or cancel.

NXOpen will throw an error if you attempt to open a part that is already open in the session. It is up to you, as the programmer, to catch and handle that error. The code below uses a Try Catch block; if the file is already open it displays a message. If desired, you could add code to switch the display part instead of showing a message. Before running the code, edit it to point to a part file of your choosing. On the first run, the part will open; on subsequent runs you will get a message telling you the file is already open. If a different error is encountered (such as "file not found"), it will report the error number and message.

Option Strict Off
Imports System
Imports NXOpen

Module open_part

Dim theSession As Session = Session.GetSession()
Dim lw As ListingWindow = theSession.ListingWindow

Sub Main()
lw.Open()

Dim basePart1 As NXOpen.BasePart = Nothing
Dim partLoadStatus1 As NXOpen.PartLoadStatus = Nothing

Try
basePart1 = theSession.Parts.OpenActiveDisplay("C:\temp\wheel.prt", NXOpen.DisplayPartOption.AllowAdditional, partLoadStatus1)
Catch ex As NXException
If ex.ErrorCode = 1020004 Then
lw.WriteLine("the file is already open, ignore this open request or change the displayed part to the one in session")
Else
lw.WriteLine("there was an error while opening the part")
lw.WriteLine(ex.ErrorCode & ": " & ex.Message)
End If
End Try

End Sub

End Module

Thank you for your comment! I actually found the issue, the problem was I didn't use
workPart = theSession.parts.work
dispPart = thesession.parts.display
c = dispPart.ComponentAssembly
right after opening a new part. I'm not using try and catch right now because this is purely test code and I want to get errors so I can solve them.

'Journal to recursively walk through the assembly structure
' will run on assemblies or piece parts
' will step through all components of the displayed part
'NX 7.5, native
'NXJournaling.com February 24, 2012

Option Strict Off

Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies

Module NXJournal

Public theSession As Session = Session.GetSession()
Public ufs As UFSession = UFSession.GetUFSession()
Public lw As ListingWindow = theSession.ListingWindow

Public workPart As NXOpen.Part = theSession.Parts.Work
Public dispPart as NXOpen.Part = theSession.Parts.Display
Public fileNameNoExt As String
Public basePart1 As NXOpen.BasePart = Nothing
Public partLoadStatus1 As NXOpen.PartLoadStatus = Nothing

Public PartNames(0) As String
Public FLART(3) as string
Public ArrayIndex as integer = 0
Public i as integer
Public j as integer
Public match as integer = 0
Public theUISession As UI = UI.GetUI
Public c As ComponentAssembly = dispPart.ComponentAssembly

Sub Main()

FLART(0) = "PART1"
FLART(1) = "PART2"
FLART(2) = "ASSEMBLY1"
FLART(3) = "PART3"

lw.Open

for i = 0 to 3

'TRIES TO OPEN THE PART SPECIFIED IN THE ARRAY
basePart1 = theSession.Parts.OpenActiveDisplay("@DB/" & FLART(i) & "/" & 1, NXOpen.DisplayPartOption.AllowAdditional, partLoadStatus1)
workPart = theSession.parts.work
dispPart = thesession.parts.display
c = dispPart.ComponentAssembly

lw.writeline("ForLoop: " & i)
lw.writeline("not isnothing " & IsNothing(c.RootComponent))

if not IsNothing(c.RootComponent) then

if ArrayIndex = 0 then
lw.writeline("Is first part and is an assembly")
fileNameNoExt = c.RootComponent.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
PartNames(ArrayIndex) = FileNameNoExt
lw.WriteLine("Assembly: " & PartNames(ArrayIndex))
ArrayIndex = ArrayIndex + 1
else
lw.writeline("Not first part and is an assembly")
Redim Preserve PartNames(ArrayIndex)
fileNameNoExt = c.RootComponent.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
for j = 0 to UBound(PartNames)
if fileNameNoExt = PartNames(j) then
match = 1
end if
next
if match <> 1 then
PartNames(ArrayIndex) = fileNameNoExt
ArrayIndex = ArrayIndex + 1
end if
match = 0

end if

'*** insert code to process 'root component' (assembly file)
lw.WriteLine(" + Active Arrangement: " & c.ActiveArrangement.Name)
'*** end of code to process root component
ReportComponentChildren(c.RootComponent, 0)
else
'*** insert code to process piece part

lw.writeline("Piece Part")
if ArrayIndex = 0 then

lw.writeline("First Part is a Piece Part")

dispPart = theSession.Parts.Display
fileNameNoExt = dispPart.FullPath
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
lw.writeline("FileNameNoExt: " & fileNameNoExt) 'WRITES THE NAME OF THE OBJECT TO THE LISTING WINDOW
PartNames(ArrayIndex) = fileNameNoExt
ArrayIndex = ArrayIndex + 1

else

lw.writeline("Not First part and is Piece Part")

dispPart = theSession.Parts.Display
Redim Preserve PartNames(ArrayIndex)
fileNameNoExt = dispPart.FullPath
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
for j = 0 to UBound(PartNames)
if fileNameNoExt = PartNames(j) then
match = 1
end if
next
if match <> 1 then
PartNames(ArrayIndex) = fileNameNoExt
ArrayIndex = ArrayIndex + 1
end if
match = 0

end if

end if

theSession.CleanUpFacetedFacesAndEdges()
theSession.Parts.Display.Close(BasePart.CloseWholeTree.True, BasePart.CloseModified.UseResponses, Nothing)

next
for j = 0 to UBound(PartNames)
lw.writeline(PartNames(j))
next
lw.Close

End Sub

'**********************************************************
Sub reportComponentChildren( ByVal comp As Component, _
ByVal indent As Integer)

For Each child As Component In comp.GetChildren()
'*** insert code to process component or subassembly
fileNameNoExt = Child.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
for j = 0 to UBound(PartNames)
if fileNameNoExt = PartNames(j) then
match = 1
end if
next
if match <> 1 then
Redim Preserve PartNames(ArrayIndex)
PartNames(ArrayIndex) = fileNameNoExt
lw.writeline("I added at the 3rd bottom most level")
ArrayIndex = ArrayIndex + 1
end if
match = 0
'*** end of code to process component or subassembly
if child.GetChildren.Length <> 0 then
for each children as component in child.getchildren()
'*** this is a subassembly, add code specific to subassemblies
fileNameNoExt = children.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
for j = 0 to UBound(PartNames)
if fileNameNoExt = PartNames(j) then
match = 1
end if
next
if match <> 1 then
Redim Preserve PartNames(ArrayIndex)
PartNames(ArrayIndex) = fileNameNoExt
lw.writeline("I added at the 2nd bottom most level")
ArrayIndex = ArrayIndex + 1
end if
match = 0
next
'*** end of code to process subassembly
else
'this component has no children (it is a leaf node)
fileNameNoExt = Child.DisplayName
fileNameNoExt = fileNameNoExt.Substring(0, Len(fileNameNoExt)-2) 'GETS THE DISPLAYED PART NAME AND TRIMS OFF TWO LETTERS FROM THE STRING IN ORDER TO REMOVE THE FORWARD SLASH AND REVISION NUMBER
for j = 0 to UBound(PartNames)
if fileNameNoExt = PartNames(j) then
match = 1
end if
next
if match <> 1 then
Redim Preserve PartNames(ArrayIndex)
PartNames(ArrayIndex) = fileNameNoExt
lw.writeline("I added at the bottom most level")
ArrayIndex = ArrayIndex + 1
end if
match = 0
end if
reportComponentChildren(child, indent + 1)
Next
End Sub
'**********************************************************
Public Function GetUnloadOption(ByVal dummy As String) As Integer
Return Session.LibraryUnloadOption.Immediately
End Function
'**********************************************************

End Module

I do recommend using Try Catch blocks even in test code; this way you can learn about the errors that you encounter without it completely crashing your code (which happens on occasion).