- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
How can I get the Item Quantity from a Structured or Model Data BOM View over all levels, Iterate Rows but how.
I know how to do a for each on all the BOM rows and compare the value with what I'm looking for.
But that level is not deep enough do I need to dive in the Child Rows I suppose.
I've tried that without success .
In other rules I've used iterate rows with succes.
I think my main issue is that I do not know/understand what to do too make the existing rule iterate.
It seems correct that you have to assign the BOM in another sub as the iterate function or sub?
Please help.
Function RecurseBOMRow(oBOMRows As BOMRowsEnumerator, Component As Document) As Integer
For Each oBOMRow In oBOMRows'.ChildRows
Dim oCompDef As ComponentDefinition
oCompDef = oBOMRow.ComponentDefinitions.Item(1)
If oCompDef.Document.FullFileName Like Component.FullFileName Then
QTY = oBOMRow.ItemQuantity()
' sw.WriteLine("Match: " & "oBOMRow.ItemQuantity: " & oBOMRow.ItemQuantity)
Return QTY
Exit Function
End If
'Call SetRowProps(oCompDef, oBOMRow.TotalQuantity)
If Not oBOMRow.ChildRows Is Nothing
Call RecurseBOMRow(oBOMRow.childrows, Component)
End If
Next
End FunctionFunction GetQTY_StructuredBOM(oDoc As Document, Component As Document)As Integer
Dim oAssyDef As AssemblyComponentDefinition = oDoc.ComponentDefinition
Dim oBOM As BOM = oAssyDef.BOM
oBOM.StructuredViewEnabled = True
oBOM.StructuredViewFirstLevelOnly = False
'oBOM.PartsOnlyViewEnabled = True
'Dim oBOMView As BOMView = oBOM.BOMViews.Item(1) ' Model Data, see also Phantom Assemblies
Dim oBOMView As BOMView = oBOM.BOMViews.Item("Structured")
'Dim oBOMView As BOMView = oBOM.BOMViews.Item("Parts Only")
'RecurseBOMRow(oBOMView.BOMRows, Component)
Dim oBOMRow As BOMRow
Dim oCompDef As ComponentDefinition
' sw.WriteLine("")
' sw.WriteLine("GetQTY_StructuredBOM")
' sw.WriteLine("Search BOMrows in doc: " & oDoc.DisplayName)
' sw.WriteLine("Search for Comp: " & Component.FullFileName)
' sw.WriteLine("BOMRows.Count: " & oBOMView.BOMRows.Count)
' sw.WriteLine("")
If Component.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
RecurseBOMRows(oBOMView.BOMRows, oDoc, Component)
End If
''''' For Each oBOMRow In oBOMView.BOMRows
''''' ' Set a reference to the primary ComponentDefinition of the row
''''' oCompDef = oBOMRow.ComponentDefinitions.Item(1)
'''''' Dim QTY_Of_Item As String
'''''' QTY_Of_Item = oBOMRow.ItemQuantity()
'''''' Dim Path_And_File_Name As String
'''''' Path_And_File_Name = oCompDef.Document.FullFileName
'''''' Dim BOM_Structure As String
'''''' BOM_Structure = oBOMRow.BOMStructure
'''''' List = List & vbCrLf & QTY_Of_Item & " - " & Path_And_File_Name & " - " & BOM_Structure
'''''' sw.WriteLine(List)
''''' If oCompDef.Document.FullFileName Like Component.FullFileName Then
''''' QTY = oBOMRow.ItemQuantity()
''''' sw.WriteLine("Match: " & "oBOMRow.ItemQuantity: " & oBOMRow.ItemQuantity)
''''' End If
'''''' If Not oBOMRow.ChildRows Is Nothing Then
'''''' Call GetQTY_StructuredBOM(oBOMRow.ChildRows, indent +2,"","")
'''''' End If
''''' Next
'MsgBox(List)
'sw.WriteLine("QTY AT END GetQTY_StructuredBOM : " & QTY & " " & oDoc.DisplayName)
Return QTY
End Function
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi @checkcheck_master. I'm sure there are other similar examples out there, but this is an example of one that I have used before. The Sub being used is fairly similar to your first Function code. I simplified the Sub Main code just for this example, so I'm sure you will want to use a different means to specify which document you want to find the total quantity of. And of course there are other ways of doing something like this, without using the BOM, depending on your specific requirements and the details of your scenario.
Sub Main
If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
MsgBox("An Assembly Document must be active for this rule to work. Exiting.", vbCritical, "")
Exit Sub
End If
Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
oBOM = oADoc.ComponentDefinition.BOM
oBOM.StructuredViewEnabled = True
oBOM.StructuredViewFirstLevelOnly = False
oBOMView = oBOM.BOMViews.Item("Structured")
Dim oDocToCountQtyOf As Document = oADoc.ReferencedDocuments.Item(3)
Dim oTotalQty As Integer = 0
ProcessBOMRowsRecursively(oBOMView.BOMRows, oDocToCountQtyOf, oTotalQty)
MsgBox("Total Quantity found = " & oTotalQty, , "")
End Sub
Sub ProcessBOMRowsRecursively(oBOMRows As BOMRowsEnumerator, oDocToFind As Document, ByRef oTotalQty As Integer)
For Each oRow As BOMRow In oBOMRows
If oRow.BOMStructure = BOMStructureEnum.kPhantomBOMStructure Or _
oRow.BOMStructure = BOMStructureEnum.kReferenceBOMStructure Then
Continue For
End If
Dim oCD As ComponentDefinition = Nothing
oCD = oRow.ComponentDefinitions.Item(1)
If TypeOf oCD Is VirtualComponentDefinition Then Continue For
Dim oRowDoc As Document = Nothing
oRowDoc = oCD.Document
If oRowDoc Is oDocToFind Then
oTotalQty = oTotalQty + oRow.ItemQuantity
'oTotalQty = oTotalQty + oRow.TotalQuantity
End If
If Not oRow.ChildRows Is Nothing Then
ProcessBOMRowsRecursively(oRow.ChildRows, oDocToFind, oTotalQty)
End If
Next
End Sub
Sometimes I choose to use an additional Sub or Function to do the core functionality, then simply call that one within my recursive routine, in order to keep the recursive routine simpler and cleaner looking. But that's just situational preference.
Edit: I mistakenly posted an older version of the code as a Function earlier, then updated the code to the new Sub version later. I often have several versions of some of my codes stored in various places. Sometimes I did not change their names and get older versions confused with newer versions. I've got to do some house cleaning on my file system. ![]()
If this solved your problem, or answered your question, please click ACCEPT SOLUTION.
Or, if this helped you, please click (LIKE or KUDOS)
.
If you want and have time, I would appreciate your Vote(s) for My IDEAS :bulb: or you can Explore My CONTRIBUTIONS
Wesley Crihfield
(Not an Autodesk Employee)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Thanks WCrihfield, I'll check it out right away.
What are your thoughts on retrieving Parent document and Parent document BomStructure from the BOMView?
What do you think is the best method?
This is what I used now but I'm wondering if there is any better.
For Each oBOMRow In oBOMRows
' Let's only get the first definition
' It would only be more than one if rows were merged
Dim oDef As ComponentDefinition
oDef = oBOMRow.ComponentDefinitions(1)
Dim partNumber As String
partNumber = oDef.Document.PropertySets("{32853F0F-3444-11D1-9E93-0060B03C1CA6}")("Part Number").value
Dim oDoc As Document = oBOMRow.ComponentDefinitions.Item(1).Document
Dim Parent As Document = oDoc.ReferencingDocuments.Item(1)
Dim oParentDocFile As Document
oParentDocFile = Parent
BOM_Parent = GetBOMStructure(oParentDocFile.ComponentDefinition.BOMStructure)
'If GetBOMStructure(oBOMRow.BOMStructure) Like filter Or GetProp(oDoc, "IUDP", "Fabrication") Like "*W*" Then
'If GetProp(oDoc, "IUDP", "Fabrication") Like "*W*" Then
If oBOMRow.ComponentDefinitions.Item(1).Document.FullFileName Like "**" Then
One more question, if I want to show all the properties but some don't exist, is there a standard way to have it so no error message or should I make a Sub with a Try Catch in it?
I don't like a whole pile of try catches
And what is the best method to retrieve them, is there a right or wrong, is one more stable than the other?
With a separate sub I can show when the code has no value.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
One more question I'd like to ask you.
When I'm going through the BOM View and want to collect/put an Assembly with all its child parts in a separate folder.
What is the best method for that?
Recursively run through the assembly based on Occurrences or through the Child Rows of the BOM.
What are the pros and cons of this or maybe there is something better.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi @checkcheck_master. Document parent is sort of the wrong terminology for what we are looking for, but even what we are looking for here is like smoke and mirrors. Sometimes it does not exist...sometimes if there should be one, it will not be found...sometimes there will be multiple and will return the wrong one. Even though the Document object has a Parent property, its value is a generic Object, and will usually just return the Application object, instead of whatever assembly document or component definition this document may be directly referenced within as a component. Using the Document.ReferencingDocuments route, depends on the higher level documents being currently either initialized or open (in-memory) to find them, then if the document is more than one level deep in an assembly, it may return the top level assembly along with every other sub assembly it is in above that point, and it may not be obvious which one of the multiple to choose without seeing the list and choosing the right one.
In my test using the iLogic code below and a testing assembly document, I chose a part that was within a weldment sub assembly, and that weldment was a top level component. In this situation, the top level assembly, and the weldment sub assembly were both in the list of documents referencing the part, but the weldment sub assembly was the second one in the list, not the first. (Components representing that part were also within the top level of the assembly.) Here is the code I used for that test.
Dim oADoc As AssemblyDocument = ThisDoc.Document
oADef = oADoc.ComponentDefinition
oOccs = oADef.Occurrences
'top level sub assembly weldment
oTopOcc = oOccs.ItemByName("Weldment BOM sample:1")
'part within that sub assembly
oSubOcc = oTopOcc.Definition.Occurrences.ItemByName("Part1:1")
Dim oSubOccDoc As Document = oSubOcc.ReferencedDocumentDescriptor.ReferencedDocument
Dim oParentDoc As Document = Nothing
'this won't work...returns Application
'oParentDoc = oSubOccDoc.Parent
oUpRefDocs = oSubOccDoc.ReferencingDocuments
If oUpRefDocs.Count = 0 Then
MsgBox("No In-Memory Documents found referencing this doc.", , "")
ElseIf oUpRefDocs.Count = 1 Then
oParentDoc = oUpRefDocs.Item(1)
ElseIf oUpRefDocs.Count > 1 Then
'oParentDoc = oUpRefDocs.Item(1)
'or
Dim oUpRefDocNames As New List(Of String)
For Each oUpRefDoc As Document In oUpRefDocs
oUpRefDocNames.Add(oUpRefDoc.FullDocumentName)
Next
oUpRefDocName = InputListBox("", oUpRefDocNames, "", "Referencing Documents", "List Of Referencing Documents")
For Each oUpRefDoc As Document In oUpRefDocs
If oUpRefDoc.FullDocumentName = oUpRefDocName Then
oParentDoc = oUpRefDoc
End If
Next
End If
If oParentDoc Is Nothing Then
MsgBox("No 'Parent' doc found.", , "")
Else
Dim oBOMStr As BOMStructureEnum = oParentDoc.ComponentDefinition.BOMStructure
MsgBox("'Parent' doc name = " & oParentDoc.FullDocumentName & vbCrLf & _
"and its BOMStructure is set to " & oBOMStr.ToString, , "")
End If
Pertaining to checking iProperties:
As far as retrieving several iPropeties from multiple documents and the right process for it to avoid errors...I would have to say that if it can be done without using a Try...Catch block and still avoid errors, then that is likely the best route, but if you don't know of any other way to avoid expected potential errors, then use the Try...Catch block. In cases concerning things like Parameters & iProperties, you can usually just loop through them to find whether or not the parameter or property exists, either using something like a Boolean variable, or a pre-defined variable to hold the found object. Then after the loop, check your Boolean or your variable to see if it is False or Nothing. That is often the better alternative, when possible, instead of a Try...Catch block. However, I generally advise folks to keep the contents within the Try...Catch block as brief, simple, and to the point as possible. Just the one problem line, or just the few lines that are testing an error prone object/method. And I also generally advise folks to make use of the Catch side, instead of just leaving it empty. Even if it's just to write something about the error to the logger in the background. It can be a huge help if/when you need to debut problems later.
Pertaining to putting an assembly and its children into a folder, and possible iteration techniques:
I assume you are talking about a BrowserFolder in the model BrowserPane? I would assume that when you move the assembly into a folder that all its children would also automatically stay with the assembly, into the folder, unless I'm missing some sort of special detail. As far as which iteration process is best...it is probably just a personal preference, rather than necessity or advantage in many situations, but I suppose if you are looking for quantities, then that's part of what the BOM is for, so that might be a more logical choice. For most other tasks I personally usually prefer iterating the assembly by either its ReferencedDocuments or its Occurrences, depending on what I'm trying to accomplish. But I generally just don't need to work with the BOM by code as heavily or with as much customization as a lot of others, so I may be leaning that way due to being far more familiar with it.
Wesley Crihfield
(Not an Autodesk Employee)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Thanks WCrihfield, you have provided me with a lot of valuable information, you don't want to know how happy I am with this.
I conclude that I have to be very careful with using Parent relations to make certain subdivisions or not, thanks for this insight.
It's also good to see this confirmed, sometimes I doubt whether I'm observing it correctly.
For example, we use a Phantom assembly with Weldments to get all underlying sub-weldment assemblies in a physical folder.
I determined on the basis of the parent relation whether it had to do with such a folder.
I'm going to use a custom property for that that controls that.
Much more flexible too.
In response to your question 'I assume you are talking about a BrowserFolder in the model BrowserPane?':
No, I mean a physical Directory.
I think I have enough information to fill that in.
Krieg already advised me to work from the BOMView.
That's what I'm going for for now.
With regard to Inseparable assemblies, to date we have not worked there with the argument that parts no longer appear on a total Parts Only list.
This from the point of view/demand from a supplier who wants an overview of all parts to be delivered.
When welding assemblies are Inseparable, in my opinion a simple Parts Only list will suffice to collect the other parts.
How do you view that?