The Revit API Parameter class provides a couple of value to string conversion methods, the AsValueString() and the ToString(). What differences are between them? What do they really do for us? Let us do some experiments to figure these out.
As introduced before, RevitAddinWizard provides a Revit Parameter Infoer coder which can produce a help method like the following:
public static List<RawParameterInfo> RawGetAllParametersInfo(Element e)
{
List<RawParameterInfo> paramList =
(from Parameter p in e.GetAllParameters()
select new RawParameterInfo
{
Name = p.Definition.Name,
Value = p.AsValueString(),
Group = p.Definition.ParameterGroup,
Type = p.Definition.ParameterType,
Storage = p.StorageType,
Unit = RawGetDUTString(p),
Shared = p.IsShared,
ReadOnly = p.IsReadOnly,
ID = p.IsShared ? p.GUID.ToString() :
(p.Definition as InternalDefinition).BuiltInParameter.ToString()
}).ToList();
return paramList;
}
Now let us create another help method which is almost the same as the above except for the value to string conversion method. This time we use the ToString() as follows:
public static List<RawParameterInfo> RawGetParametersInfo1(Element e)
{
List<RawParameterInfo> paramList =
(from Parameter p in e.Parameters
select new RawParameterInfo
{
Name = p.Definition.Name,
Value = p.ToString(),
Group = p.Definition.ParameterGroup,
Type = p.Definition.ParameterType,
Storage = p.StorageType,
Unit = RawGetDUTString(p),
Shared = p.IsShared,
ReadOnly = p.IsReadOnly,
ID = p.IsShared ? p.GUID.ToString() :
(p.Definition as InternalDefinition).BuiltInParameter.ToString()
}).ToList();
return paramList;
}
Ok, create some test code to test the methods out:
…
List<RawParameterInfo> paramsInfo = RawGetParametersInfo(element);
using (StreamWriter sw = new StreamWriter(@"c:\temp\ParametersInfo.csv"))
{
string title = string.Empty;
string rows = RawParametersInfoToCSVString(paramsInfo, ref title);
sw.WriteLine(title);
sw.Write(rows);
}
List<RawParameterInfo> paramsInfo1 = RawGetParametersInfo1(element);
using (StreamWriter sw = new StreamWriter(@"c:\temp\ParametersInfo1.csv"))
{
string title = string.Empty;
string rows = RawParametersInfoToCSVString(paramsInfo1, ref title);
sw.WriteLine(title);
sw.Write(rows);
}
…
Their output for a selected wall may look like the following respectively.
The output corresponding to the AsValueString() call:
Name,Value,Group,Type,Storage,Unit,Shared,ID,ReadOnly
Mark,,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_MARK,False
Location Line,,PG_CONSTRAINTS,Invalid,Integer,,False,WALL_KEY_REF_PARAM,False
Unconnected Height,10' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_USER_HEIGHT_PARAM,True
Top Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_EXTENSION_DIST_PARAM,True
Top Offset,0' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_OFFSET,False
Length,83' - 7 95/256",PG_GEOMETRY,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,CURVE_ELEM_LENGTH,True
Top is Attached,,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_TOP_IS_ATTACHED,True
Base is Attached,,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_BOTTOM_IS_ATTACHED,True
Phase Demolished,,PG_PHASING,Invalid,ElementId,,False,PHASE_DEMOLISHED,False
Related to Mass,,PG_CONSTRAINTS,YesNo,Integer,,False,RELATED_TO_MASS,True
Phase Created,,PG_PHASING,Invalid,ElementId,,False,PHASE_CREATED,False
Volume,710.46 CF,PG_GEOMETRY,Volume,Double,DUT_CUBIC_FEET,False,HOST_VOLUME_COMPUTED,True
Base Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BOTTOM_EXTENSION_DIST_PARAM,True
Comments,,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_INSTANCE_COMMENTS,False
Room Bounding,,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_ATTR_ROOM_BOUNDING,False
Area,718.50 SF,PG_GEOMETRY,Area,Double,DUT_SQUARE_FEET,False,HOST_AREA_COMPUTED,True
Base Constraint,,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_BASE_CONSTRAINT,False
Structural Usage,,PG_STRUCTURAL,Invalid,Integer,,False,WALL_STRUCTURAL_USAGE_PARAM,False
Top Constraint,,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_HEIGHT_TYPE,False
Base Offset,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BASE_OFFSET,False
The output corresponding to the ToString() call for the same selected wall:
Name,Value,Group,Type,Storage,Unit,Shared,ID,ReadOnly
Length,Autodesk.Revit.DB.Parameter,PG_GEOMETRY,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,CURVE_ELEM_LENGTH,True
Top is Attached,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_TOP_IS_ATTACHED,True
Volume,Autodesk.Revit.DB.Parameter,PG_GEOMETRY,Volume,Double,DUT_CUBIC_FEET,False,HOST_VOLUME_COMPUTED,True
Base Extension Distance,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BOTTOM_EXTENSION_DIST_PARAM,True
Structural Usage,Autodesk.Revit.DB.Parameter,PG_STRUCTURAL,Invalid,Integer,,False,WALL_STRUCTURAL_USAGE_PARAM,False
Base Constraint,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_BASE_CONSTRAINT,False
Top Constraint,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_HEIGHT_TYPE,False
Top Offset,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_OFFSET,False
Base is Attached,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_BOTTOM_IS_ATTACHED,True
Base Offset,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BASE_OFFSET,False
Location Line,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Invalid,Integer,,False,WALL_KEY_REF_PARAM,False
Comments,Autodesk.Revit.DB.Parameter,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_INSTANCE_COMMENTS,False
Area,Autodesk.Revit.DB.Parameter,PG_GEOMETRY,Area,Double,DUT_SQUARE_FEET,False,HOST_AREA_COMPUTED,True
Top Extension Distance,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_EXTENSION_DIST_PARAM,True
Room Bounding,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_ATTR_ROOM_BOUNDING,False
Phase Demolished,Autodesk.Revit.DB.Parameter,PG_PHASING,Invalid,ElementId,,False,PHASE_DEMOLISHED,False
Phase Created,Autodesk.Revit.DB.Parameter,PG_PHASING,Invalid,ElementId,,False,PHASE_CREATED,False
Unconnected Height,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_USER_HEIGHT_PARAM,True
Related to Mass,Autodesk.Revit.DB.Parameter,PG_CONSTRAINTS,YesNo,Integer,,False,RELATED_TO_MASS,True
Mark,Autodesk.Revit.DB.Parameter,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_MARK,False
For concise and focus purposes here, the class RawParameterInfo is not appended. It can be found in previous posts.
Both CSV text contents and spreadsheet screenshots are provided to demonstrate the output clearly. As can be noticed, the ToString() does nothing at all. It only prints out the Parameter type full name which is the default implementation of any .NET types.
The AsValueString() addresses only DOUBLE storage type parameters in our case. It does not care about the String, Inteter, and ElementId strorage types. So it looks like confusions would have been avoided if the method were named as AsDoubleValueString(), ToUnitValueString(), or something like that.
Ok, a question comes up. Is there a straightforeard way to convert the various parameter values to a string?
No. We have to do the conversion outsevles based on the StorageType or even ParameterType of each Parameter.
It is not a big deal. The following externsion method is such an example:
public static string ToValueString(this Autodesk.Revit.DB.Parameter p)
{
string ret = string.Empty;
switch (p.StorageType)
{
case StorageType.ElementId:
ret = p.AsElementId().ToString();
break;
case StorageType.Integer:
ret = p.AsInteger().ToString();
break;
case StorageType.String:
ret = p.AsString();
break;
case StorageType.Double:
ret = p.AsValueString();
break;
default:
break;
}
return ret;
}
Here is another version of the parameter infoer:
public static List<RawParameterInfo> RawGetParametersInfo2(Element e)
{
List<RawParameterInfo> paramList =
(from Parameter p in e.Parameters
select new RawParameterInfo
{
Name = p.Definition.Name,
Value = p.ToValueString(),
Group = p.Definition.ParameterGroup,
Type = p.Definition.ParameterType,
Storage = p.StorageType,
Unit = RawGetDUTString(p),
Shared = p.IsShared,
ReadOnly = p.IsReadOnly,
ID = p.IsShared ? p.GUID.ToString() :
(p.Definition as InternalDefinition).BuiltInParameter.ToString()
}).ToList();
return paramList;
}
Here is the test code:
…
List<RawParameterInfo> paramsInfo2 = RawGetParametersInfo2(element);
using (StreamWriter sw = new StreamWriter(@"c:\temp\ParametersInfo2.csv"))
{
string title = string.Empty;
string rows = RawParametersInfoToCSVString(paramsInfo2, ref title);
sw.WriteLine(title);
sw.Write(rows);
}
…
Here is the output for the same wall as selected before:
Name,Value,Group,Type,Storage,Unit,Shared,ID,ReadOnly
Volume,710.46 CF,PG_GEOMETRY,Volume,Double,DUT_CUBIC_FEET,False,HOST_VOLUME_COMPUTED,True
Base Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BOTTOM_EXTENSION_DIST_PARAM,True
Phase Created,118390,PG_PHASING,Invalid,ElementId,,False,PHASE_CREATED,False
Base Offset,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BASE_OFFSET,False
Base is Attached,0,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_BOTTOM_IS_ATTACHED,True
Room Bounding,1,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_ATTR_ROOM_BOUNDING,False
Length,83' - 7 95/256",PG_GEOMETRY,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,CURVE_ELEM_LENGTH,True
Location Line,2,PG_CONSTRAINTS,Invalid,Integer,,False,WALL_KEY_REF_PARAM,False
Top Offset,0' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_OFFSET,False
Top Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_EXTENSION_DIST_PARAM,True
Structural Usage,0,PG_STRUCTURAL,Invalid,Integer,,False,WALL_STRUCTURAL_USAGE_PARAM,False
Area,718.50 SF,PG_GEOMETRY,Area,Double,DUT_SQUARE_FEET,False,HOST_AREA_COMPUTED,True
Comments,Comments by spiderinnet,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_INSTANCE_COMMENTS,False
Base Constraint,30,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_BASE_CONSTRAINT,False
Related to Mass,0,PG_CONSTRAINTS,YesNo,Integer,,False,RELATED_TO_MASS,True
Phase Demolished,-1,PG_PHASING,Invalid,ElementId,,False,PHASE_DEMOLISHED,False
Mark,Marked by spiderinnet,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_MARK,False
Unconnected Height,10' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_USER_HEIGHT_PARAM,True
Top is Attached,0,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_TOP_IS_ATTACHED,True
Top Constraint,9946,PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_HEIGHT_TYPE,False
As can be seen, all different kinds of values have string representations now.
It may still be confusing a bit as the ElementId and Integer storage type parameters are not differentiated in the output.
What about the following improved version?
public static string ToValueDisplayString(this Autodesk.Revit.DB.Parameter p)
{
string ret = string.Empty;
switch (p.StorageType)
{
case StorageType.ElementId:
ret = string.Format("ElementId( {0} )", p.AsElementId());
break;
case StorageType.Integer:
if (p.Definition.ParameterType == ParameterType.YesNo)
{
ret = p.AsInteger() == 0 ? "No" : "Yes";
}
else
{
ret = p.AsInteger().ToString();
}
break;
case StorageType.String:
ret = p.AsString();
break;
case StorageType.Double:
ret = p.AsValueString();
break;
default:
break;
}
return ret;
}
Here is the test code:
List<RawParameterInfo> paramsInfo3 = RawGetParametersInfo3(element);
using (StreamWriter sw = new StreamWriter(@"c:\temp\ParametersInfo3.csv"))
{
string title = string.Empty;
string rows = RawParametersInfoToCSVString(paramsInfo3, ref title);
sw.WriteLine(title);
sw.Write(rows);
}
Here is the output content:
Name,Value,Group,Type,Storage,Unit,Shared,ID,ReadOnly
Top Constraint,ElementId( 9946 ),PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_HEIGHT_TYPE,False
Unconnected Height,10' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_USER_HEIGHT_PARAM,True
Top Offset,0' - 4",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_OFFSET,False
Base Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BOTTOM_EXTENSION_DIST_PARAM,True
Length,83' - 7 95/256",PG_GEOMETRY,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,CURVE_ELEM_LENGTH,True
Structural Usage,0,PG_STRUCTURAL,Invalid,Integer,,False,WALL_STRUCTURAL_USAGE_PARAM,False
Phase Demolished,ElementId( -1 ),PG_PHASING,Invalid,ElementId,,False,PHASE_DEMOLISHED,False
Location Line,2,PG_CONSTRAINTS,Invalid,Integer,,False,WALL_KEY_REF_PARAM,False
Base Constraint,ElementId( 30 ),PG_CONSTRAINTS,Invalid,ElementId,,False,WALL_BASE_CONSTRAINT,False
Mark,Marked by spiderinnet,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_MARK,False
Comments,Comments by spiderinnet,PG_IDENTITY_DATA,Text,String,,False,ALL_MODEL_INSTANCE_COMMENTS,False
Area,718.50 SF,PG_GEOMETRY,Area,Double,DUT_SQUARE_FEET,False,HOST_AREA_COMPUTED,True
Base Offset,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_BASE_OFFSET,False
Volume,710.46 CF,PG_GEOMETRY,Volume,Double,DUT_CUBIC_FEET,False,HOST_VOLUME_COMPUTED,True
Related to Mass,No,PG_CONSTRAINTS,YesNo,Integer,,False,RELATED_TO_MASS,True
Top is Attached,No,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_TOP_IS_ATTACHED,True
Base is Attached,No,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_BOTTOM_IS_ATTACHED,True
Phase Created,ElementId( 118390 ),PG_PHASING,Invalid,ElementId,,False,PHASE_CREATED,False
Top Extension Distance,0' - 0",PG_CONSTRAINTS,Length,Double,DUT_FEET_FRACTIONAL_INCHES,False,WALL_TOP_EXTENSION_DIST_PARAM,True
Room Bounding,Yes,PG_CONSTRAINTS,YesNo,Integer,,False,WALL_ATTR_ROOM_BOUNDING,False
Here is the spreadsheet screenshot:
The value display looks nicer, doesn’t it? Of course, you can always tail the code to meet any other particular needs. For example, the value -1 of ElementId may seem better to be expressed literally as BAD or INVALID. Enjoy!
As can be noticed, we also got some side findings.
- The order of the parameters returned by the Element.Parameters property is random, meaning they are not ordered at all.
- The ParameterType of many parameters, which have good StorageType, Name, BuiltInParameterGroup, and Value, returns Invalid, which is confusing.
The random order thing is not a big deal. We can order the returned parameters as what we like.
The Invalid ParameterType issue is not so serious either. Once we bear in mind that the ParameterType should not be used to detect the goodness of any parameters things are just fine.
RevitAddinWizard coders use proper versions of the parameter value to string conversion methods when necessary.
Recent Comments