Revit family parameter (FamilyParameter) shares a lot of properties such as BuiltInParameterGroup, ParameterType, StorageType, and DisplayUnitType with the model parameter and has some unique ones as well such as IsReporting, IsInstance and CanAssignFormula as we discussed previously.
Another very special character of the FamilyParameter is that it does not store a value itself. Instead, its value has to be retrieved from each FamilyType instance individually. It behaves very different from model/element Parameter in this regard. For example, each element has a Property collection and each Property carries a value, but the FamilyParameter collection has a single copy in the FamilyManager object of each Family Document and each FamilyType can have a different value for the same FamilyParameter.
So we have to find a FamilyParameter from somewhere, the FamilyManager.Parameters property, and retrieve its value from somewhere else, through the methods AsInteger(), AsDouble(), AsString(), and AsElementId() of FamilyType.
In this post, let’s see how to retrieve values of all FamilyParameter instances regarding all available FamilyType objects in a family document, organize the values and any associated information in a good store center, and make it ready to use.
The following help method stores the FamilyParameter name and value of all FamilyParameter instances and the name of each associated FamilyType into a dictionary which has nested lists as entries:
Public Shared Function NameToTypeValuesMap(ByVal famMan As FamilyManager) As Dictionary(Of String, List(Of KeyValuePair(Of String, Object)))
Dim fpNameToTypeValuesMap As New Dictionary(Of String, List(Of KeyValuePair(Of String, Object)))()
For Each p As FamilyParameter In famMan.Parameters
Dim typeValuePairs As New List(Of KeyValuePair(Of String, Object))()
For Each type As FamilyType In famMan.Types
Select Case p.StorageType
Case StorageType.Double
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, type.AsDouble(p)))
Exit Select
Case StorageType.Integer
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, type.AsInteger(p)))
Exit Select
Case StorageType.String
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, type.AsString(p)))
Exit Select
Case StorageType.ElementId
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, type.AsElementId(p)))
Exit Select
Case StorageType.None
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, "N/A"))
Exit Select
Case Else
typeValuePairs.Add(New KeyValuePair(Of String, Object)(type.Name, Nothing))
Exit Select
End Select
Next
fpNameToTypeValuesMap.Add(p.Definition.Name, typeValuePairs)
Next
Return fpNameToTypeValuesMap
End Function
And the following code will convert the informative dictionary into a single CSV string:
Public Function FamilyParameterValuesInfoToCSVString(ByVal values As Dictionary(Of String, List(Of KeyValuePair(Of String, Object))), ByRef title As String) As String
title = "Parameter Name,Family Type,Parameter Value"
Dim sb As New StringBuilder()
For Each kvp As KeyValuePair(Of String, List(Of KeyValuePair(Of String, Object))) In values
sb.Append(kvp.Key + ",," + Environment.NewLine)
For Each pair As KeyValuePair(Of String, Object) In kvp.Value
sb.Append("," + pair.Key & ",")
sb.Append((If(pair.Value Is Nothing, "null", pair.Value.ToString())) + Environment.NewLine)
Next
Next
Return sb.ToString()
End Function
Then we can write all the FamilyParameter value information of an opened family document to a CSV file.
…
If CachedDoc.IsFamilyDocument Then
Dim fpNameToTypeValuesMap As Dictionary(Of String, List(Of KeyValuePair(Of String, Object))) = NameToTypeValuesMap(CachedDoc.FamilyManager)
Using sw As New StreamWriter("c:\FamilyParameterValuesInfo.csv")
Dim title As String
Dim rows As String = FamilyParameterValuesInfoToCSVString(fpNameToTypeValuesMap, title)
sw.WriteLine(title)
sw.Write(rows)
End Using
End If
…
Finally the CSV file can be read into a spreadsheet of Excel.
Parameter Name Family Type Parameter Value
Leg Height
60" x 30" Student 0.5
72" x 36" 0.5
60" x 30" 0.5
Depth
60" x 30" Student 2.5
72" x 36" 3
60" x 30" 2.5
Model
60" x 30" Student null
72" x 36" null
60" x 30" null
Top Material
60" x 30" Student 7590
72" x 36" 7590
60" x 30" 7590
Manufacturer
60" x 30" Student null
72" x 36" null
60" x 30" null
Handle/Leg Material
60" x 30" Student 8052
72" x 36" 8052
60" x 30" 8052
Body Material
60" x 30" Student 7589
72" x 36" 7589
60" x 30" 7589
Description
60" x 30" Student null
72" x 36" null
60" x 30" null
Cost
60" x 30" Student null
72" x 36" null
60" x 30" null
Width
60" x 30" Student 5
72" x 36" 6
60" x 30" 5
Height
60" x 30" Student 2.5
72" x 36" 2.5
60" x 30" 2.5
Keynote
60" x 30" Student null
72" x 36" null
60" x 30" null
Assembly Code
60" x 30" Student E2020200
72" x 36" E2020200
60" x 30" E2020200
URL
60" x 30" Student null
72" x 36" null
60" x 30" null
Type Comments
60" x 30" Student null
72" x 36" null
60" x 30" null
From the output, we can notice something that is not so straightforward:
- The value of some string StorageType FamilyParameter instances may be null instead of empty. So please keep this in mind as accessing properties like Length or calling methods like Replace() from/on the string object will throw out a null-object-reference exception in this case.
- Apparently the ToString() has been implemented in the ElementId class as converting the id integer value to a string and returning it. So no need to explicitly do the conversion like ElementId.IntegerValue.ToString().
The informative indexed lists can be used for any other purposes as well for sure.
FamilyParameter Value Collector of RevitAddinWizard can help do all of these in C# or VB.NET.
Recent Comments