Getting List of Items in Named Model Tree Folder

Getting List of Items in Named Model Tree Folder

e_frissell
Advocate Advocate
440 Views
7 Replies
Message 1 of 8

Getting List of Items in Named Model Tree Folder

e_frissell
Advocate
Advocate

Looking for some help with an iLogic script I'm trying to write to create a list of ship loose items - first part that's commented out is looking for an iProperty on parts/assemblies which works, but the second part is what's giving me headaches.  The reason I need the second part is for things like fasteners that we use in multiple places where the iProperty shouldn't be assigned, so for that case I figured it was easier to dump items into a folder in the model tree.  I can get to the folder using the below code but trying to figure out what's in the folder has me stumped... Checked the iLogic documents and BrowserNode is supposed to be able to get contents of a folder however nothing in there seems to suggest it can get the items in the folder.

 

Dim oDoc As Document = ThisDoc.Document
Dim refDoc As Document
Dim shiplooseItems As New System.Text.StringBuilder()
Dim shipMethod, refDocPN As String

'Logger.Info("")

' this successfully finds the iProperty ShippingMethod and determines if it is loose or not
'For Each refDoc In oDoc.AllReferencedDocuments
'	Dim custPropSet As PropertySet
'	Dim pnPropSet As PropertySet
'	custPropSet = refDoc.PropertySets.Item("Inventor User Defined Properties")
'	pnPropSet = refDoc.PropertySets.Item("Design Tracking Properties")
	
'		Try :
'			shipMethod = custPropSet.Item("ShippingMethod").Value
'			If shipMethod = "Loose" Then 
'				refDocPN = pnPropSet("Part Number").Value
'				Logger.Info(refDocPN & " is ship loose")
'			End If
'		Catch :
'			GoTo Skip :
'		End Try
		
			
'	Skip :
	
'Next

For Each refDoc In oDoc.AllReferencedDocuments
	If refDoc.DocumentType = kAssemblyDocumentObject Then
		Dim oPane As BrowserPane = refDoc.BrowserPanes.Item("Model")
		Dim oTargetNode As BrowserNode = oPane.TopNode
		Dim folderName As String
		
		If oTargetNode.BrowserFolders.Count > 0 Then
			For Each xFolder In oTargetNode.BrowserFolders
				folderName = xFolder.Name
				If InStr(folderName, "oose") > 0 Then 
					' get item names and qty inside xFolder
					Dim oFolder As BrowserFolder = oTargetNode.BrowserFolders.Item(folderName)
					Logger.Info(refDoc.DisplayName & ": " & xFolder.Name) ' correctly finds folder
					

					'Next
					
				End If
			Next
		End If
	End If
Next

 

0 Likes
441 Views
7 Replies
Replies (7)
Message 2 of 8

WCrihfield
Mentor
Mentor

Hi @e_frissell.  In Line 41, you are getting the folder that you already have a reference to, by its name, which you just got a couple lines earlier.  The 'xFolder' variable is already representing that same exact folder, so no need to get that folder again.

 

Also, to get the items within a BrowserFolder, you need to get the BrowserFolder.BrowserNode, then use its BrowserNode.BrowserNodes property to access the 'child' nodes of that node.  It is not like 'regular' folders in a file system.  They are primarily just symbolic in this context.  Then you may need to check BrowserNode.NativeObject property value, then check which Type you got from it.  You may need to use a Try...Catch...End Try statement when getting the native object, because that causes an error for some nodes.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 8

e_frissell
Advocate
Advocate

Thanks @WCrihfield !  That helped a bunch and I'm able to list out the items in folder.  I can't say if this is the right way forward but it's a way - one concern I have is if something is a pattern, I can probably identify it by looking for "pattern" in the string oNode.FullPath but if it's renamed to something like "Asm1 Fasteners" I'm not sure it'll pick it up?  Do you know if there's a way to determine whether or not a node is a pattern without using it's name?

 

BrowserNodeDefinition.Type will return 50387456 however API documentation states "Contains the definition of a native-created node in the browser." And I'm not really sure what that means

 

 

If InStr(xFolder.Name, "oose") > 0 Then 
					' get item names and qty of items in folder
					Dim oFolder As BrowserFolder = oTargetNode.BrowserFolders.Item(xFolder.Name)
					'Logger.Info(refDoc.DisplayName & ": " & xFolder.Name) ' correctly finds folder
					For Each oNode In oFolder.BrowserNode.BrowserNodes
						Logger.Info(oNode.BrowserNodeDefinition.Label)
					Next

 

 

0 Likes
Message 4 of 8

WCrihfield
Mentor
Mentor

Hi @e_frissell.

First, create a variable as Object Type, without a value. Then later, use a Try...Catch to set the value of that variable from oNode.NativeObject property, to avoid the potential error.  Then after that, check if that variable 'Is Nothing' first, then use TypeName(oNativeObj) (a vb.net Function) to get the String of its Type.  This Type name will most likely include "Pattern" in it, so you can check that.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 8

e_frissell
Advocate
Advocate

Thanks again, I did incorporate that and the variable oNodeType comes back as the kNativeBrowserNodeDefinitionObject and, just to see the difference, I used the TypeName and that comes back as ObjectTypeEnum which needs to be one level deeper...

https://help.autodesk.com/view/INVNTOR/2020/ENU/?guid=GUID-2A00689F-4FCA-4810-87CC-2E4EF1B9586E

 

 

					For Each oNode In oFolder.BrowserNode.BrowserNodes
						'Logger.Info("Node Type: " & oNode.BrowserNodeDefinition.Type)
							Try :
								oNodeType = oNode.BrowserNodeDefinition.Type
								Logger.Info("Node Type: " & oNodeType)
								Logger.Info("Node Object Type: " & TypeName(oNode.BrowserNodeDefinition.Type))
							Catch :
								If oNodeType Is Nothing Then
									oNodeCatch = TypeName(oNode.BrowserNodeDefinition.Type)
									Logger.Info("Node Object Type: " & oNodeCatch )
								End If
							End Try

 

0 Likes
Message 6 of 8

WCrihfield
Mentor
Mentor

Not using BrowserNodeDefinion or the .Type property, using the .NativeObject property's value, like this:

For Each oNode As BrowserNode In oFolder.BrowserNode.BrowserNodes
	Dim oNativeObj As Object = Nothing 'created within loop, and set to Nothing
	Dim sType As String = String.Empty 'also created within the loop, and set to empty String
	Try
		oNativeObj = oNode.NativeObject
		sType = TypeName(oNativeObj)
		Logger.Info("Node NativeObject Type: " & sType)
	Catch 'what to do if the 'Try' task caused an error
		'do nothing here, or maybe skip to next Node
		Continue For 'this would force it to skip to next node, since it failed
	End Try
	If oNativeObj Is Nothing Then
		Continue For
	Else 'something was obtained
		If sType.Contains("Pattern") Then
			'you know that the oNativeObj represents some type of pattern
			'so do something with that pattern here, if needed
			'not sure what you want to do
		End If
	End If
Next 'oNode

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 7 of 8

e_frissell
Advocate
Advocate

Oh wow, that worked perfectly!  I see why you referenced the NativeObject property, I didn't understand it at the time...

 

Mind if I ask why you create the variable oNativeObj as well as sType within the loop and not prior?  I'm sure when to properly define the variable is handled on a case by case basis, but for this case would it have something to do with the variable resetting to 'nothing' on each iteration?


I guess to better explain this, and maybe solicit any suggestions, the intent here is... When we ship a machine we're required to have a document noting all the items that are shipped loose with the machine, however filling that document out is a bit of a source of tribal knowledge and I'm attempting to eliminate that by creating iProperties on parts/assemblies that are always shipped loose, or by placing parts/assemblies in folders in the model tree.  So, the long and short of it is that to make the document work the script needs to be able to generate the name of each item in a folder as well as the number of instances of that item.  The goal then is to write this information to an Excel file for people to reference. There will probably be a few hurdles with this but getting that pattern identification out of the way is a huge help

 

It wouldn't have made more sense to count each component occurrence within the folder would it?  I think I saw some code where that was recommended but couldn't figure out if it was possible...

 

 

 

 

0 Likes
Message 8 of 8

WCrihfield
Mentor
Mentor

First, I will attempt to explain creating variables inside vs outside of an iteration (loop):

  • Creating them before the loop, is often considered to 'perform' better, when processing speed is an important issue.
  • Creating them before the loop, allows any code after the loop to access those variables, and any values they may have been given within the loop, if they are needed after the loop.
  • If they are not needed after the loop, and the very slight performance difference is not an issue, then creating them inside the loop is preferred.  Because this will cause the value of that variable to be carried over from the previous iteration, when that is often not wanted, and the alternative is to use another line of code within the start of the loop to set that variable back to Nothing or an empty/default value.

As for why I used both variables (oNativeObj & sType), its because these are two different types of values.  I figured you will need to know what Type of object the 'Node' is a placeholder for, and then, once you know which Type it is, you will need to use that 'NativeObject' itself, to get further information about it.  For instance, you could have a long Select Case statement, or a long If...ElseIf...ElseIf...End If statement, with one 'check' for each Type of object you are expecting, and when it is that Type, you create a new variable of that Type, then set the NativeObject as that variable's value.  Then you can access all the regular properties & methods of that specific object's Type.

 

For example, if the NativeObject is a ComponentOccurrence Type object.

If TypeOf oNativeObj Is ComponentOccurrence Then
'or
If sType = "ComponentOccurrence" Then
Dim oOcc As ComponentOccurrence = oNativeObj
oOcc.Name
oOcc.Definition.Document
... and so on, using it as needed

But if you can get all you need from the oNode.BrowserNodeDefinition.Label property value, or the oNode.FullPath property, then you may not need to get the actual object itself, with full access to all its properties and such.

 

Finding, and reporting about which items in an assembly are 'shipped loose' is not something I have to deal with myself.  But my first thoughts were about instance properties, if some of a certain kind are not 'shipped loose', while others of that same type are 'shipped loose'.  Another thing that comes to mind is attributes.  But both are not very 'visible', and attributes can only be accessed by API code means, or an add-in, so neither is especially user friendly.  I have always disliked navigating the model browser tree though, if I can avoid it any other way.  I am not sure if it would be faster to iterate all components, checking if each is in a specific folder in the model browser tree, but that sounds very labor intensive to me.  Checking another aspect of each one would be less so.  I don't suppose these specifications could be set at the referenced document level, could they.  Likely some of the files involved may be ReadOnly for one reason or another, which may eliminate that option.  If that were possible though, you could iterate referenced documents, check some detail about them, then get all the occurrences in your assembly that reference that document, to get your count.  Just some thoughts.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes