Announcements

Starting in December, we will archive content from the community that is 10 years and older. This FAQ provides more information.

Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to NOT set a parameter in an occurrence document with model states

8 REPLIES 8
Reply
Message 1 of 9
CattabianiI
534 Views, 8 Replies

How to NOT set a parameter in an occurrence document with model states

Setting a parameter in an occurrence you get an exception if factory document is loaded (and open) in memory.
Setting a parameter in an occurrence via factory document does not raise an exception, but you may be setting the parameter in the wrong model state.

 

 

Dim paramName As String = "test_param_name"
Dim paramVal As Integer 

Dim asmDoc As Inventor.AssemblyDocument = ThisDoc.Document

' Get part document of the first occurrence
Dim partDoc As PartDocument = asmDoc.ComponentDefinition.Occurrences.Item(1).Definition.Document

Dim prtCmpDef As PartComponentDefinition = partDoc.ComponentDefinition
If prtCmpDef.IsModelStateMember Then
	Dim facDoc As Document = prtCmpDef.FactoryDocument
	If facDoc.Open Then
		If facDoc.ModelStateName <> partDoc.ModelStateName Then
			MsgBox("You're going to set param in the wrong model state")
		Else
			MsgBox("Setting param via factory document is gonna be ok")
		End If
		partDoc = facDoc
	Else
		MsgBox("Setting param via member document is gonna be ok")
	End If
End If

Dim prtDocUserParams As UserParameters = partDoc.ComponentDefinition.Parameters.UserParameters

Dim param As UserParameter = Nothing

Try
	' Check if param already exists
	param = prtDocUserParams.Item(paramName)
	paramVal = param.Value + 1
Catch ex As Exception
	' Param does not exist
	Logger.Info("This parameter does not exist: {0}.", paramName)
	paramVal = 1
End Try

If param IsNot Nothing
	' if param exists set the expression
	param.Value = paramVal
	' same errore using iLogic method
	' Parameter("NEW236A9F8D:1", "test_param_name") = paramExpr
Else
	' Create missing param
	prtDocUserParams.AddByValue(paramName, paramVal, UnitsTypeEnum.kMillimeterLengthUnits)
End If

iLogicVb.UpdateWhenDone = True

 

 








Labels (1)
8 REPLIES 8
Message 2 of 9
WCrihfield
in reply to: CattabianiI

Hi @CattabianiI.  I'm not sure I understand, because it is an odd question, but I think your code will always succeed because of this line:

partDoc = facDoc

Because that 'partDoc' variable pre-existed that loop, and us used later for getting the parameters.  So it will always be working with the 'factory' document, and therefore should always work.  So, if you want it to 'not work', then I would say remove that line...but I'm not sure if that's what you are after here.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 9
WCrihfield
in reply to: CattabianiI

Another similar situation is when you have multiple top level components in your assembly that all represent the same base part, but each one is set to a different ModelState version of that base part, and one is also set to its 'Master/Primary' ModelState.  That then means that each version of that model is now 'open' in memory.  In situations like that, I may go the extra process of ensuring that I am working with the correct version of the model by visibly opening the model file, then check which ModelState is currently 'active', and if its not the one that the component was set to, I 'activate' that one, then make sure the EditMemberScope is set the right way, then proceed to do the edits, then close (visibly) the document.  I believe the document needs to be visibly open before you can 'activate' one of its ModelStates, or change EditMemberScope.

PS.  You can also do this with the Documents.Open, if you supply the FullDocumentName that includes the name of the ModelState that you want to be working with.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 4 of 9
CattabianiI
in reply to: CattabianiI

Hi @WCrihfield, it's not a real question, I would like a linkable post where I explain why snippet like this one are not ok.


Because this line

partDoc = facDoc

 makes the code succeed but could have changed the parameter in an unintended model state. You can see the behavior in the attached video. 

It's a post to point out how difficult to work with model state is. 

There is a solution (or let's say a workaround) I implemented in my AddIns, based on do the modification via model state table: it's long and tricky, certainly not something iLogic is intended for imho.



Message 5 of 9
CattabianiI
in reply to: WCrihfield

In situations like that, I may go the extra process of ensuring that I am working with the correct version of the model by visibly opening the model file [...] check which ModelState is currently 'active', and if its not the one that the component was set to, I 'activate' that one

Yeah that's definitely a workaround, the document could already be open though, maybe in a substitute model state; and activate model state could be a slow task, and that's why I prefer to work via the model state table.

Message 6 of 9
WCrihfield
in reply to: CattabianiI

OK.  I see it now.  Even though your code will succeed to edit a component's parameters every time, it may be changing the parameter within the wrong ModelState, because the code is not actually doing anything to direct the value to the 'matching' ModelState, just letting the user know that it will be going to the wrong one.  And simply working with the 'factory' document is not enough.  You must make sure the 'factory' document represents the same ModelState that the component is currently set to, which isn't always portrayed clearly.  When you do get the 'factory' document version of the model, you must then check which ModelState is 'active' in that version of the document, then if it is not the same one that your component is currently set to, you must either 'activate' the correct ModelState within the document before you will be editing the right version, or you must attempt to edit the ModelStateTable directly.  This process is definitely a lot more complicated than it used to be before ModelStates existed.  It took me quite a while, and a lot of testing to figure them out too.

 

I wrote this contribution post about ModelStates and the different versions of the document that are involved.

Inventor's ModelStates and their 'Member' vs 'Factory' Document References Explained 

My first/early interpretation was that the 'factory' document was the version of the model that was not under the influence of any of its ModelStates (except the Master/Primary), but of course I soon figured out that was wrong, even though it sounds like a logical assumption.  And also found out that there is not always a 'factory' version of every model document.  Only documents that have more than the one original ModelState are going to have a 'factory' document.  And also found out that the Document.FullDocumentName always reflects which ModelState a document is under the influence of.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 9
WCrihfield
in reply to: CattabianiI

Hi @CattabianiI.  I know that you said you already have something like this within your AddIn, but you inspired me to look into my own similar Sub routine type solution for editing the 'ModelStateTable' to set parameter values, instead of going the 'open and activate' type route, because I haven't messed with it in a while.  And as you mentioned, it is quite long in comparison to similar routines that do not attempt to edit the table.  Event the name of the Sub routine I am using is quite long, because I have several different similar routines I was testing with, and was trying to keep them unique enough.

 

This example below is one I created specifically for working with components in an assembly.  The Sub routine itself doesn't cause the component within the main assembly to visibly update to reflect the new value, so I added a few lines to my Main sub routine for updating the component afterwards, because it may be time consuming to do it each time in a large assembly.  It is not 100% 'fool proof' yet, because it does not account for if the model does not have any custom ModelStates, in which case it will obviously not find a ModelStateTable to mess with.  So it is only used on components that I know have custom ModelStates.  This can be checked before calling the Sub to run, but where's the fun in that, since the routine is already pretty long.

Sub Main
	Dim oADoc As AssemblyDocument = ThisDoc.Document
	Dim oOcc As ComponentOccurrence = oADoc.ComponentDefinition.Occurrences.ItemByName("Part3:2")
	If IsNothing(oOcc) Then
		MsgBox("Component not found.",,"") : Exit Sub
	End If
	SetComponentModelStateTableParamExpression(oOcc, "Length", "6")
	Dim oCompDoc As Document = ThisApplication.Documents.ItemByName(oOcc.ReferencedDocumentDescriptor.FullDocumentName)
	If oCompDoc.RequiresUpdate Then oCompDoc.Update
	If oCompDoc.Dirty Then oCompDoc.Save
	If 	oADoc.RequiresUpdate Then oADoc.Update
End Sub

Sub SetComponentModelStateTableParamExpression(oComp As ComponentOccurrence, _
oParamName As String, oParamExpression As String)
	If IsNothing(oComp) Or oParamName = "" Or oParamExpression = "" Then Exit Sub
	Dim oCompFacDoc As Document = Nothing
	If oComp.Definition.IsModelStateMember Then
		oCompFacDoc = oComp.Definition.FactoryDocument
	Else
		oCompFacDoc = oComp.Definition.Document
	End If
	Dim oMSs As ModelStates = oCompFacDoc.ComponentDefinition.ModelStates
	Dim oTable As ModelStateTable = oMSs.ModelStateTable
	Dim oCol As ModelStateTableColumn
	Try
		oCol = oTable.TableColumns.Item(oParamName)
	Catch
		Logger.Debug("A ModelStateTableColumn named " & oParamName & " was not found," _
		& vbCrLf & "in the following document:" & vbCrLf & oCompFacDoc.FullDocumentName)
		Exit Sub
	End Try
	Dim oRow As ModelStateTableRow
	Try
		oRow = oTable.TableRows.Item(oComp.ActiveModelState)
	Catch
		Logger.Debug("A ModelStateTableRow named " & oComp.ActiveModelState & " was not found," _
		& vbCrLf & "in the following document:" & vbCrLf & oCompFacDoc.FullDocumentName)
		Exit Sub
	End Try
	Dim oCell As ModelStateTableCell = oRow.Item(oCol)
	Try
		Dim oVal As String = oCell.Value
		oCell.Value = oParamExpression
		Logger.Info("The parameter named " & oParamName & vbCrLf & _
		"within the following document:  " & oCompFacDoc.FullDocumentName & _
		vbCrLf & "was changed from " & oVal & " to " & oParamExpression)
	Catch oEx As Exception
		MsgBox("Error attempting to set new value to ModelStateTableCell." & vbCrLf & _
		oEx.Message & vbCrLf & oEx.StackTrace, vbCritical, "")
	End Try
End Sub

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 8 of 9
CattabianiI
in reply to: WCrihfield

It's pretty long and still doesn't work if the parameter is not in model state table!

To do something like that, the section where you look for the column can be modified with the following lines:

Dim isParamNotInTable As Boolean = False
Try
  oCol = oTable.TableColumns.Item(oParamName)
Catch
  Logger.Debug("A ModelStateTableColumn named " & oParamName & " was not found," _
  & vbCrLf & "in the following document:" & vbCrLf & oCompFacDoc.FullDocumentName)
  isParamNotInTable = True
  'Exit Sub
End Try

If isParamNotInTable Then
  oCol = AddParamInTable(oParamName, oTable, oCompFacDoc)
End If
Function AddParamInTable(oParamName As String, oTable As ModelStateTable, oCompFacDoc As Document) As ModelStateTableColumn
	' Get param in active model state
	Dim param As Inventor.Parameter
	Try
		param = oCompFacDoc.Componentdefinition.Parameters.Item(oParamName)
	Catch
		Return Nothing
	End Try

	Dim origParamValue = param.Value
	If param.Units = "Text" Then
		Throw New NotImplementedException()
	ElseIf param.Units = "Boolean" Then		
		Throw New NotImplementedException()
	Else
		' Set param in the active model state to make its column available in table
		param.Value = origParamValue + 1
		' Set back param to its previous value
		param.Value = origParamValue
	End If

	Dim mstCol As ModelStateTableColumn = oTable.TableColumns.Item(oParamName)

	Return mstCol
End Function


In Inv 2021 it was just a single line, now an iLogic user have to consider all the things we pointed out here!
This is not what iLogic is intended for. 


Message 9 of 9
WCrihfield
in reply to: CattabianiI

I agree that this process has been greatly complicated, and it could use some additional tools, both within the iLogic AddIn, and in the regular Inventor API system, to help make it not only easier, but also less susceptible to causing mistakes and unintentional edits.  So much of the iLogic only stuff, as well as the Inventor API stuff lacks sufficient basic documentation in the online help system.  I wish we had more influence to suggest and effect changes in that documentation, to include more detailed descriptions, examples, warnings, and the like.  I have used the tools at the bottoms of many online help pages to suggest corrections to entries that were clearly not correct, as well as suggesting a lot of additional or clearer descriptions & documentation, but I don't know if any of it is making any difference or not.

 

For instance the iLogic snippets for working with Parameters in the 'local' or 'active' document.  There are a couple which are heavily used, because they return (and let you set) the value in 'document units'.  However, if my parameter is in Feet, or Yards, but my document is set to Inches, I am still not able to 'get' or 'set' the value in its proper units (the units that the parameter is set to)...not the document's units, or the 'database' units.  And the Parameter API object itself only returns values in 'database' units, unless you attempt to interpret its Expression String, which isn't always ideal.  So, in light of this, I also have to have my own custom developed Sub/Function type routines for working with plain parameters in documents that do Not use any ModelStates.  After all these years, this should not still be the case.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report