VBA code to Read existing Custom iProperty or Create if not present

VBA code to Read existing Custom iProperty or Create if not present

arkelec
Collaborator Collaborator
6,086 Views
18 Replies
Message 1 of 19

VBA code to Read existing Custom iProperty or Create if not present

arkelec
Collaborator
Collaborator

I've read a few threads & other online resources with VBA code to create & update iProperties, but my VBA knowledge is pants.  So I'm stuck.

 

Is it possible to create a function that will read any custom iProperties & if the ones I want added  don't already exist, add them?

 

Thanks.

0 Likes
Accepted solutions (3)
6,087 Views
18 Replies
Replies (18)
Message 2 of 19

arkelec
Collaborator
Collaborator
Accepted solution

OK, with a bit more perseverance, if worked it out.

 

Here's the code (in case anyone else finds it useful, or has any improvement):

Sub UpdateRangeParameters()

    UpdatePartDescription
    UpdatePartNº
    UpdateManufacturer
    UpdateVendorPartNº
    UpdateVendorPrice

End Sub

Private Sub UpdatePartDescription()
' Get the active part document.
Dim Doc As Document
Set Doc = ThisApplication.ActiveDocument


' Get the custom property set.
Dim customPropSet As PropertySet
'Set customPropSet = invPartDoc.PropertySets.Item("User Defined Properties")
Set customPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")


' Attempt to get an existing custom property named "Part_Description".
On Error Resume Next
Dim Part_Description As Property
Set Part_Description = customPropSet.Item("Part_Description")
If Err.Number <> 0 Then
    ' Property does not exist -> Add the property.
    Dim textValue As String
    textValue = "Part Description"
    Call customPropSet.Add(textValue, "Part_Description")
End If

End Sub

Private Sub UpdatePartNº()
' Get the active part document.
Dim Doc As Document
Set Doc = ThisApplication.ActiveDocument


' Get the custom property set.
Dim customPropSet As PropertySet
'Set customPropSet = invPartDoc.PropertySets.Item("User Defined Properties")
Set customPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")


' Attempt to get an existing custom property named "Part_Description".
On Error Resume Next
Dim Part_Nº As Property
Set Part_Nº = customPropSet.Item("Part_Nº")
If Err.Number <> 0 Then
    ' Property does not exist -> Add the property.
    Dim textValue As String
    textValue = "Part Nº"
    Call customPropSet.Add(textValue, "Part_Nº")
End If

End Sub

Private Sub UpdateManufacturer()
' Get the active part document.
Dim Doc As Document
Set Doc = ThisApplication.ActiveDocument


' Get the custom property set.
Dim customPropSet As PropertySet
'Set customPropSet = invPartDoc.PropertySets.Item("User Defined Properties")
Set customPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")


' Attempt to get an existing custom property named "Part_Description".
On Error Resume Next
Dim Manufacturer As Property
Set Manufacturer = customPropSet.Item("Manufacturer")
If Err.Number <> 0 Then
    ' Property does not exist -> Add the property.
    Dim textValue As String
    textValue = "Manufacturer"
    Call customPropSet.Add(textValue, "Manufacturer")
End If

End Sub

Private Sub UpdateVendorPartNº()
' Get the active part document.
Dim Doc As Document
Set Doc = ThisApplication.ActiveDocument


' Get the custom property set.
Dim customPropSet As PropertySet
'Set customPropSet = invPartDoc.PropertySets.Item("User Defined Properties")
Set customPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")


' Attempt to get an existing custom property named "Part_Description".
On Error Resume Next
Dim Vendor_Part_Nº As Property
Set Vendor_Part_Nº = customPropSet.Item("Vendor_Part_Nº")
If Err.Number <> 0 Then
    ' Property does not exist -> Add the property.
    Dim textValue As String
    textValue = "Vendor_Part_Nº"
    Call customPropSet.Add(textValue, "Vendor_Part_Nº")
End If

End Sub

Private Sub UpdateVendorPrice()
' Get the active part document.
Dim Doc As Document
Set Doc = ThisApplication.ActiveDocument


' Get the custom property set.
Dim customPropSet As PropertySet
'Set customPropSet = invPartDoc.PropertySets.Item("User Defined Properties")
Set customPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")


' Attempt to get an existing custom property named "Part_Description".
On Error Resume Next
Dim Vendor_Price As Property
Set Vendor_Price = customPropSet.Item("Vendor_Price")
If Err.Number <> 0 Then
    ' Property does not exist -> Add the property.
    Dim textValue As String
    textValue = "Vendor_Price"
    Call customPropSet.Add(textValue, "Vendor_Price")
End If

End Sub

Thanks to Owner2229 for the original code: how-to-update-custom-iproperties-with-vba

 

Message 3 of 19

DRoam
Mentor
Mentor
Accepted solution

You don't need to write a separate function for every iProperty. You can use a function that takes the desired iProperty name as an argument, like this:

 

Sub Main()
'If you just want to make sure the iProperties exist, use this code:
iPropGet("Part_Description")
iPropGet("PartNº")
iPropGet("Manufacturer")
iPropGet("Vendor_Part_Nº")
End Sub

Function iPropGet(PropName As String, Optional MissingSetVal As Object = "", Optional Doc As Inventor.Document = Nothing) As Object
	If Doc Is Nothing Then Doc = ThisDoc.Document
	
	Dim CustomPropSet As Inventor.PropertySet = Doc.PropertySets.Item("Inventor User Defined Properties")
	
	Try
		Dim CurrentValue As Object = CustomPropSet.Item(PropName).Value
		Return CurrentValue
	Catch
		Dim oTransaction As Inventor.Transaction
		Try
			oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc,"Create property """ & PropName & """")
				CustomPropSet.Add(MissingSetVal, PropName)
			oTransaction.End
			Return MissingSetVal 'Successfully created/set.
		Catch
			If Not oTransaction Is Nothing Then oTransaction.Abort
			Return -1 'Unable to create.
		End Try
		
		Return MissingSetVal
	End Try
End Function

If you want to specify a value to use if the iProperties don't exist, you can use the second argument of the iPropGet function, like this:

'If you want to specify a value to use if the iProperties don't exist, do so like this:
Sub Main() iPropGet("Part_Description","ValueIfMissing") iPropGet("PartNº","ValueIfMissing") iPropGet("Manufacturer","ValueIfMissing") iPropGet("Vendor_Part_Nº","ValueIfMissing") End Sub

Also, you said you want to read the value of the iProperty. If so, you'll want to assign the retrieved property value to a variable that you can use later, like this:

 

Sub Main()
'If you want to make sure they exist AND use their values, use this code:
Dim PartDescription As String = iPropGet("Part_Description","ValueIfMissing")
Dim PartNº As String = iPropGet("PartNº","ValueIfMissing")
Dim Manufacturer As String = iPropGet("Manufacturer","ValueIfMissing")
Dim Vendor_Part_Nº As String = iPropGet("Vendor_Part_Nº","ValueIfMissing")
End Sub

 

Message 4 of 19

arkelec
Collaborator
Collaborator

Thanks for your reply DRoam.

 

I'm getting some errors though - what am I doing wrong?

 

VBA iProp Code Error 1.png

I told you my VBA skills were weak Smiley Sad

0 Likes
Message 5 of 19

DRoam
Mentor
Mentor
Accepted solution

Sorry about that, I forgot you were working in VBA rather than iLogic. VBA tends to be a bit more nitpicky about things (like not declaring and initializing variables on the same line, using "Set" when setting objects, and the distinction between Variant and Object), and also doesn't support a lot of things that VB.net (what iLogic uses) does, like Try/Catch.

 

This should work for you, let me know if it doesn't:

Function iPropGet(PropName As String, Optional MissingSetVal As Variant = "", Optional Doc As Inventor.Document = Nothing) As Variant
    If Doc Is Nothing Then Set Doc = ThisApplication.ActiveDocument
    
    Dim CustomPropSet As Inventor.PropertySet
    Set CustomPropSet = Doc.PropertySets.Item("Inventor User Defined Properties")
    
    On Error GoTo CreateProp
    
    iPropGet = CustomPropSet.Item(PropName).Value
    Exit Function
        
CreateProp:
    Dim oTransaction As Inventor.Transaction
    On Error GoTo Abort
        
    Set oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc, "Create property """ & PropName & """")
        Call CustomPropSet.Add(MissingSetVal, PropName)
    oTransaction.End
    
    iPropGet = MissingSetVal
    Exit Function
    
Abort:
    If Not oTransaction Is Nothing Then oTransaction.Abort
    iPropGet = Nothing
    Exit Function
End Function

Private Sub iPropAdd()
Dim PartDescription As String
PartDescription = iPropGet("Part_Description", "ValueIfMissing")
Dim PartNº As String
PartNº = iPropGet("PartNº", "ValueIfMissing")
Dim Manufacturer As String
Manufacturer = iPropGet("Manufacturer", "ValueIfMissing")
Dim Vendor_Part_Nº As String
Vendor_Part_Nº = iPropGet("Vendor_Part_Nº", "ValueIfMissing")
End Sub
Message 6 of 19

arkelec
Collaborator
Collaborator

Thanks again DRoam.

 

I only used VBA as the other code I scrounged was.

 

I see now that VB.net can be entered into a rule - I've created a new rule to which I've added the code to launch the form which displays/edits the custom iProp values & it runs fine.

I see your point about the benefits of VB.net.

I'm using some other VBA code to create a macro so that the rule can be launched from the ribbon - I assume that this is the only way to do it?

0 Likes
Message 7 of 19

DRoam
Mentor
Mentor

@arkelec wrote:

Thanks again DRoam.

 

I only used VBA as the other code I scrounged was.

 

I see now that VB.net can be entered into a rule - I've created a new rule to which I've added the code to launch the form which displays/edits the custom iProp values & it runs fine.

I see your point about the benefits of VB.net.

I'm using some other VBA code to create a macro so that the rule can be launched from the ribbon - I assume that this is the only way to do it?


Yep! You're right on track. This is how we do it as well. Most of our scripts are in External iLogic rules, and we just use VBA to create macros for firing them from the ribbon.

 

Message 8 of 19

arkelec
Collaborator
Collaborator
Great, I've stripped out the old Rules & VBA code - it's much tidier now!

1 more question if I may.
The iProp fields are currently formatted as text. I want to add a Price field. Am I better to use text, or can I format this field as currency (or another number format)?
0 Likes
Message 9 of 19

DRoam
Mentor
Mentor

Great!

 

Good question, I guess it depends on what you're using it for. The possible iProperty types are: Text, Number, Yes/No, and Date, so out of those your options would be text and number.

 

If it's purely for displaying on drawings or something, you could make it text so you can make it look nice, like "$1,499.99". But if it could be used for calculations or something, you'd be better off storing it as a number.

 

Unlike Parameters, iProperties are versatile and can be freely switched between the various types. So if you set an iProperty to a number via iLogic, it should convert it to a numeric iProperty. And likewise for text (string), yes/no (boolean) and date.

 

Hope that helps!

0 Likes
Message 10 of 19

arkelec
Collaborator
Collaborator

Thanks again.

 

There is a problem though.  I altered the original name of function iPropGet to iPropGetStr for the string items, modifying the other refs to iPropGet accordingly.

 

Then I added the following function for the integer:

Function iPropGetInt(PropName As Integer, Optional MissingSetVal As Object = "", Optional Doc As Inventor.Document = Nothing) As Object
	If Doc Is Nothing Then Doc = ThisDoc.Document
	
	Dim CustomPropSet As Inventor.PropertySet = Doc.PropertySets.Item("Inventor User Defined Properties")
	
	Try
		Dim CurrentValue As Object = CustomPropSet.Item(PropName).Value
		Return CurrentValue
	Catch
		Dim oTransaction As Inventor.Transaction
		Try
			oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc,"Create property """ & PropName & """")
				CustomPropSet.Add(MissingSetVal, PropName)
			oTransaction.End
			Return MissingSetVal 'Successfully created/set.
		Catch
			If Not oTransaction Is Nothing Then oTransaction.Abort
			Return -1 'Unable to create.
		End Try
		
		Return MissingSetVal
	End Try
End Function

 

I changed the declaration for Vendor_Price as follows:

Dim Vendor_Price As Integer = iPropGetInt("Vendor_Price", 0.00)

All seemed OK, but then a message box with "!Conversion from string "Vendor_Price" to type 'Integer' is not valid."

 

What have I missed?

 

On a wider note, could you point me in the direction of some good tutorials?  I really need to up my game with the iLogic environment.

0 Likes
Message 11 of 19

arkelec
Collaborator
Collaborator

0 Likes
Message 12 of 19

DRoam
Mentor
Mentor

Sorry about that, slipped under my radar. Thanks for the nudge.

 

Actually, the original "iPropGet" function from my first post should be able to handle both text and numeric iProperties (and even yes/no and Date ones as well). So you don't need to use a separate "iPropGetInt" function.

 

I think the error is actually not occurring within the function itself, but when the result of the function is assigned to the "Vendor_Price" integer variable. I suspect the Vendor_Price iProperty already exists, with the TEXT value "Vendor_Price", when you run the rule? If so, that's what's causing the error. The function is getting the current value of the iProperty just fine, but it's a text value ("Vendor_Price") so when it tries to assign that to the Vendor_Price boolean variable, it throws the error.

 

If this is something that's a possibility in your datasets (iProperties could already exist with the wrong data type), then you could handle that by having the iPropGet function check if the iProperty's current value's type matches the type of the "MissingSetVal" you supplied, and if it doesn't, treat it like the iProperty is "missing" and set its value to the MissingSetVal. The function as modified below will do that. Note that it needs the supporting function "CompatibleTypes".

 

Function iPropGet(PropName As String, Optional MissingSetVal As Object = "", Optional Doc As Inventor.Document = Nothing) As Object
	If Doc Is Nothing Then Doc = ThisDoc.Document
	
	Dim CustomPropSet As Inventor.PropertySet = Doc.PropertySets.Item("Inventor User Defined Properties")
	
	Dim oTransaction As Inventor.Transaction
	Try
		Dim oProp As Inventor.Property = CustomPropSet.Item(PropName)
		If CompatibleTypes(oProp.Value,MissingSetVal) = False Then
			oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc,"Edit property """ & PropName & """")
				oProp.Value = MissingSetVal
			oTransaction.End
			Return MissingSetVal 'Successfully set to proper type.
		End If
		
		Return CurrentValue 'Already exists and propert type.
	Catch
		Try
			oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc,"Create property """ & PropName & """")
				CustomPropSet.Add(MissingSetVal, PropName)
			oTransaction.End
			Return MissingSetVal 'Successfully created.
		Catch
			If Not oTransaction Is Nothing Then oTransaction.Abort
			Return -1 'Unable to create.
		End Try
		
		Return MissingSetVal
	End Try
End Function

Function CompatibleTypes(Var1,Var2) As Boolean
	Try
		Dim EqualityCheck As Boolean = (Var1 = Var2)
		Return True 'Equality check successful. Types are compatible.
	Catch
		Return False 'Equality check unsuccessful. Types are incompatible.
	End Try
End Function

You can use this function to check for text, number, yes/no, and date iProperties. You just have to supply a MissingSetVal to let it know which type it's checking for.

Message 13 of 19

DRoam
Mentor
Mentor

Oh, and I forgot to mention, you'll want to use the "Double" type rather than "Integer" for the price, because Integer will only store the whole-number ("dollars") portion, it won't be able to store the decimal ("cents") portion.

Message 14 of 19

arkelec
Collaborator
Collaborator

Cheers for the reply.

Changing the data type to Double worked straight away, so I think you're right, I'd inadvertently entered some weird data mismatch loop.

I'll try the other code later.

#nothavingagoodday

0 Likes
Message 15 of 19

arkelec
Collaborator
Collaborator

Hi DRoam, sorry that this is dragging on, but an issue still persists.

If I add anything to 2 decimal places, the filed is converted to text.

I have no idea.

This is the code:

Dim Vendor_Price As Double = iPropGetStr("Vendor_Price", 0.0000)

 

I want the price format to be up to 4 decimal places.

 

To test this, I make sure that there is no custom iProp called Vendor_Price.

 

Assembly Custom iProp 01.png

After running the rule, the form I have created is loaded:

Custom Doc Form 01.png

 

The format is to 1 decimal place, but still a number:

Assembly Custom iProp 02.png

 

So I load the custom form & add a price:

Custom Doc Form 02.png

 

But when I check the custom iProp, it's now text:

 

Assembly Custom iProp 03.png

What am I doing wrong?

 

For reference, this is the whole code in the rule:

 

 

Sub Main()
Dim iFileName As String
iFileName=ThisDoc.FileName(False) 'without extension
iProperties.Value("Custom", "File_Name") = iFileName
Dim Part_Description As String = iPropGetStr("Part_Description","Enter Part Description")
Dim Part_Nº As String = iPropGetStr("Part_Nº","Enter Part Nº")
Dim Manufacturer As String = iPropGetStr("Manufacturer","Enter Manufacturer")
Dim Vendor_Part_Nº As String = iPropGetStr("Vendor_Part_Nº", "Enter Vendor Part Nº")
Dim Vendor_Price As Double = iPropGetStr("Vendor_Price", 0.0000)
iLogicForm.Show("Document Properties")
End Sub

Function iPropGetStr(PropName As String, Optional MissingSetVal As Object = "", Optional Doc As Inventor.Document = Nothing) As Object
	If Doc Is Nothing Then Doc = ThisDoc.Document
	
	Dim CustomPropSet As Inventor.PropertySet = Doc.PropertySets.Item("Inventor User Defined Properties")
	
	Try
		Dim CurrentValue As Object = CustomPropSet.Item(PropName).Value
		Return CurrentValue
	Catch
		Dim oTransaction As Inventor.Transaction
		Try
			oTransaction = ThisApplication.TransactionManager.StartTransaction(Doc,"Create property """ & PropName & """")
				CustomPropSet.Add(MissingSetVal, PropName)
			oTransaction.End
			Return MissingSetVal 'Successfully created/set.
		Catch
			If Not oTransaction Is Nothing Then oTransaction.Abort
			Return -1 'Unable to create.
		End Try
		
		Return MissingSetVal
	End Try
End Function

 

 

 

 

 

 

 

 

 

 

 

 

0 Likes
Message 16 of 19

DRoam
Mentor
Mentor

No problem, iProperty data types can be finicky.

 

I'm pretty sure I know what's going on. The culprit is most likely the input form. Forms will always set iProperties to the data type they had when they were added to the form originally. So my guess is, when that form was created, the "Vendor_Price" iProperty was in the Text format. So now, even though the iLogic has created it in the Number format, as soon as you change it using the form, the form is converting it to the Text format.

 

The fix for this is simple -- just delete Vendor_Price from your form, then make sure the iProperty exists in the current document as a number, and then re-add it to the form. Then, whenever you edit Vendor_Price using the form, the form will always set it as a number rather than as text.

 

Let me know if that works for you.

Message 17 of 19

arkelec
Collaborator
Collaborator

Hi, thanks, yes that seems to work.  I did wonder about the form myself, but couldn't see anywhere for the format.

However...is there a way of displaying zero's trailing the decimal point to 4 figures?  Or even 2?

 

Custom Doc Form 03.png

0 Likes
Message 18 of 19

DRoam
Mentor
Mentor

Yeah, it would be nice if the form editor would tell you which format the iProperty field is using.

 

And unfortunately, no, I don't think there's a way to do any kind of format control using the form. If you really need a formatted iProperty, your best bet would probably be to create rule like this, that will format a secondary dedicated text property for the price, based on the numeric iProperty's value:

 

Dim Price_Num As Double = iPropGet("Vendor_Price",0.00)
Dim DesiredText As String = "$" & Price_Num.ToString("0.0000")

Dim CurrentText As String = iPropGet("Vendor_Price_Formatted","")
If Not CurrentText = DesiredText Then iProperties.Value("Custom","Vendor_Price_Formatted") = DesiredText

Make that an External rule so you can add to or modify it if needed, and add it to the "iProperty Change" event trigger so it'll always keep the formatted version updated with the numeric version.

 

Then you can add the formatted version to your form, and make it read-only, so you can easily verify that it's correct:

 

Formatted Text Property.png

 

It should always update whenever the Vendor_Price iProperty is changed. I try to avoid stacking iLogic onto keeping iProperties up to date like this, but sometimes it's unavoidable. 

Message 19 of 19

arkelec
Collaborator
Collaborator

Thanks again DRoam.

 

I've had a bit of a re-think as the end goal has somewhat shifted.  I'm going to leave this thread now as you've answered my original questions (and more).

 

I'm still struggling with other aspects of VB.Net so I'm going to create new threads to deal with the specifics.

 

Please keep an eye out for them, I'd really appreciate your input.

0 Likes