Community,
I have an assembly design that uses an iLogic Form and multiple Rules to configure the model.
I have discovered the value of DataTables to store common info.
The challenge - I need multiple rules to have access to these DataTables.
Currently, the DataTable is (re)defined in each Rule.
I would like to avoid this duplication.
I created an external rule to create the DataTable, but after the external rule is run, the assembly does not see the DataTable.
I tried running an external rule with arguments, but I could not return the DataTable from the external rule.
AddReference "System.Data"
AddReference "System.Xml"
Imports System.Data
Imports System.Xml
Public Class ThisRule
Sub Main()
' declare map
Dim RuleArguments As Inventor.NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap()
' set a map
RuleArguments.Value("SharedVariable") = SharedObjects.AttachmentTable
' run external rule
iLogicVb.RunExternalRule("BuildAttachmentTable", RuleArguments)
' see results
''
'' Following are lines I tested to see the returned results
MsgBox(RuleArguments.Item(0))
MsgBox(RuleArguments.Item("SharedVariable"))
End Sub
End Class
Public Class SharedObjects
Public Shared AttachmentTable As New DataTable("AttachmentTable")
End Class
How could I make an external rule create and return a DataTable to share with all rules in an assembly?
Thank you for your time and attention. I look forward to your replies.
Regards,
Jerry
Solved! Go to Solution.
Solved by WCrihfield. Go to Solution.
Hi @JBerns. I do not have much experience with DataTable objects myself, but they seem pretty similar to other non generic collections to me, and I know that I can pass a List(Of String) or an Inventor.Document to another rule using the RuleArguments, so I'm thinking that it may not be working because of the use of that other custom Class being used. Have you tried creating that DataTable directly within the main routine, then passing it into the RuleArguments, without using the custom Class? Also, have you tried using a regular iLogic SharedVariable to store it in directly?
Edit: If you need to use a custom Class, have you considered using a separate external iLogic rule, with the 'Straight VB Code' option turned on, then use the AddVBFile line in the Header of the rule to reference it. Not sure if that would help any, but that is usually a pretty good option for custom Classes.
Wesley Crihfield
(Not an Autodesk Employee)
Hi @JBerns. This may not be exactly what you were looking for, but it is a step in the right direction at least. As an example, I created two quick, simple internal iLogic rules. One for creating a DataTable, and filling in some data, then sending it to the other rule to read. Then the second rule is set up to receive that DataTable, and read it. This text example worked for me.
Below is rule 1, named "Create DataTable, Send It":
AddReference "System.Data.dll"
AddReference "System.Data.Common.dll"
AddReference "System.XML"
Imports System.Data
Sub Main
Dim oDataTable As New DataTable
Dim oCol1 As DataColumn = oDataTable.Columns.Add("Name")
oCol1.DataType = System.Type.GetType("System.String")
Dim oCol2 As DataColumn = oDataTable.Columns.Add("Age")
oCol2.DataType = System.Type.GetType("System.Int32")
Dim oRow1 As DataRow = oDataTable.Rows.Add({"Tom", 45 })
Dim oRow2 As DataRow = oDataTable.Rows.Add({"Bob", 37 })
Dim oArgs As NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap
oArgs.Add("DataTable", oDataTable)
iLogicVb.RunRule("Receive DataTable, Read It", oArgs)
End Sub
...and below is the second rule, named "Receive DataTable, Read It":
AddReference "System.Data.dll"
AddReference "System.Data.Common.dll"
AddReference "System.XML"
Imports System.Data
Sub Main
Dim oDataTable As DataTable = Nothing
If RuleArguments.Exists("DataTable") Then
oDataTable = RuleArguments.Value("DataTable")
Else
MsgBox("No DataTable Received!", vbCritical, "Nothing Received")
Exit Sub
End If
If oDataTable Is Nothing Then Exit Sub
For Each oRow As DataRow In oDataTable.Rows
Dim sName As String = oRow.Item("Name")
Dim oAge As Int32 = oRow.Item("Age")
MsgBox(sName & " is " & oAge.ToString & ".", vbInformation, "DataTable ReadOut")
Next
End Sub
When I run the first rule, I immediately see the messages pop from the second rule. So, I know that the second rule has received it, and can read/use the data within it. That settles whether or not you can send/receive a DataTable using RuleArguments. By the way, the second rule could edit the DataTable further, then respond back to the first rule, or pass it along to another rule also. If sent back to the first rule (not using RunRule method, just the RuleArguments object), and there could be more code within the first rule that will kick in and continue from there, after the second rule has finished, and do something further with that DataTable.
Wesley Crihfield
(Not an Autodesk Employee)
Thanks for the quick reply.
I have been successful at sharing a DataTable across rules within the document using a SharedVariable. Here is my code:
'Define DataTable rule
AddReference "System.Data"
AddReference "System.Xml"
Imports System.Data
Imports System.Xml
Public Class ThisRule
Public Shared oTest1 As DataTable '= New System.Data.DataTable("Test1")
Private Sub ClearColumnsCollection(table As DataTable)
Dim columns As DataColumnCollection
' Get the DataColumnCollection from a DataTable
columns = table.Columns
columns.Clear()
End Sub
Sub Main()
break
' Clear the datatable of rows
SharedObjects.oTest1.Clear
' Clear the datatable of columns
ClearColumnsCollection(SharedObjects.oTest1)
' Report column/row count before add
MsgBox("oTest1 Column Count before: " & SharedObjects.oTest1.Columns.Count & vbLf & _
"oTest1 Row Count before: " & SharedObjects.oTest1.Rows.Count _
, , "BEFORE - Inside 'Define'")
' Add two columns
SharedObjects.oTest1.Columns.Add("Perimeter", GetType(String))
SharedObjects.oTest1.Columns.Add("Area", GetType(String))
' Add two rows
SharedObjects.oTest1.Rows.Add("100", "200")
SharedObjects.oTest1.Rows.Add("200", "400")
' Report column/row count after add
MsgBox("oTest1 Column Count after: " & SharedObjects.oTest1.Columns.Count & vbLf & _
"oTest1 Row Count after: " & SharedObjects.oTest1.Rows.Count _
, , "AFTER - Inside 'Define'")
' Set the shared variable
SharedVariable("dt") = SharedObjects.oTest1
End Sub
End Class
Public Class SharedObjects
' Declare the datatable
Public Shared oTest1 As DataTable = New System.Data.DataTable("oTest1")
End Class
' View DataTables rule
AddReference "System.Data"
AddReference "System.Xml"
Imports System.Data
Imports System.Xml
Public Class ThisRule
Public Shared oTest1 As DataTable
Sub Main()
' Define the datatables
iLogicVb.RunRule("Define DataTables")
' Report column/row count
MsgBox("dt Column Count: " & SharedVariable("dt").Columns.Count & vbLf & _
"dt Row Count: " & SharedVariable("dt").Rows.Count _
, , "Inside 'View DataTables'")
End Sub
End Class
Public Class SharedObjects
' Declare the datatable
Public Shared oTest1 As DataTable '= New System.Data.DataTable("oTest1")
End Class
When you run the rule, 'View DataTables', the 'Define DataTables' rule is run which creates the SharedVariable of the datatable object.
Granted, the DataTable will contain much more data (5 columns, 500+ rows). And this is just one of about six datatables we may need.
I have not been successful at using the RuleArguments.
I have not tried AddVBFile. I will try that next.
The goal to externalize the datatable is because the common info will be used by various equipment designs (assemblies). I could consider a CSV file and read this file each time, but I think that would impact performance.
Thanks again for your feedback. I hope I am not overcomplicating the goal to have a common source of data.
Regards,
Jerry
Thanks for the RunRule with Arguments code example. This too could be useful.
Your suggestion to use AddVbFile I think will have the greatest value.
Wish I had found your forum post earlier.
I put together example external and internal rules.
External rule, BuildCustomerTable :
' <IsStraightVb>True</IsStraightVb>
Imports System.Data
Imports System.Xml
Public Class ThisRule
Public Shared CustomerTable As New DataTable("CustomerTable")
Private Sub ClearColumnsCollection(table As DataTable)
Dim columns As DataColumnCollection
' Get the DataColumnCollection from a DataTable
columns = table.Columns
' Erase the columns
columns.Clear()
End Sub
Function BuildCustomerTable() As System.Data.DataTable
' Clear the table of rows
CustomerTable.Clear
' Clear the columns
ClearColumnsCollection(CustomerTable)
' Define columns
CustomerTable.Columns.Add("Name", GetType(String))
CustomerTable.Columns.Add("Age", GetType(Integer))
CustomerTable.Columns.Add("Discount", GetType(Single))
' Add rows
CustomerTable.Rows.Add("Tom", 45, 0.05)
CustomerTable.Rows.Add("Mary", 29, 0.08)
CustomerTable.Rows.Add("Bob", 37, 0.10)
Return CustomerTable
End Function
End Class
Above is attached in the ZIP file. Note the use of the 'Straight VB' option.
And the internal rule, Report Customer Info:
AddReference "System.Data"
AddReference "System.Xml"
Imports System.Data
Imports System.Xml
AddVbFile "[YOUR PATH HERE]\BuildCustomerTable.iLogicVb"
''' Main program
'''
Sub Main()
' Build the datatable with Name, Age, Discount
BuildCustomerTable
' Verify the table exists
If Not IsNothing(CustomerTable) Then
MsgBox("Found a DataTable.")
End If
End Sub
Be sure to edit the path as needed in the AddVbFile line.
I will attach a sample part file that demonstrates searching the datatable.
Thanks again, Wes, for all the great info!
Regards,
Jerry
Can't find what you're looking for? Ask the community or share your knowledge.