Parameter offers a few set methods to assign values to different data types:
Set(ElementId)
Set(Double)
Set(Int32)
Set(String)
Obviously, the first signature is used to assign values for Parameter with ElementId StorageType and the last is for String StorageType. The middle two may confuse people: what will happen if a value of 5 is provided to the Set method of a Double StorageType Parameter and what if a value of 5.0 to of Integer StorageType?
Revit Parameter Organizer can organize various Revit parameters such as Shared Parameters, Family Parameters, Project Parameters and Built-in Parameter in many good ways.
Let’s do a simple test:
Dim wall As Wall = SelectWall(cmdData.Application.ActiveUIDocument.Selection)
Dim pLst As List(Of Parameter) = (From p In wall.Parameters Select p)
Dim str As String = String.Empty
'Double StorageType
Dim baseOffsetP As Parameter = pLst.First(Function(p) p.Definition.Name = "Base Offset")
str += vbLf & "Double StorageType:" & vbLf
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, baseOffsetP.AsDouble(), "2*3", baseOffsetP.Set(2 * 3), baseOffsetP.AsDouble())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, baseOffsetP.AsDouble(), "5", baseOffsetP.Set(5), baseOffsetP.AsDouble())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, baseOffsetP.AsDouble(), """3.3""", baseOffsetP.Set("3.3"), baseOffsetP.AsDouble())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, baseOffsetP.AsDouble(), "3/1.5", baseOffsetP.Set(3 / 1.5), baseOffsetP.AsDouble())
'Integer StorageType
Dim strucUsageP As Parameter = pLst.First(Function(p) p.Definition.Name = "Structural Usage")
str += vbLf & "Integer StorageType:" & vbLf
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, strucUsageP.AsInteger(), """2""", strucUsageP.Set("2"), strucUsageP.AsInteger())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, strucUsageP.AsInteger(), "1.0", strucUsageP.Set(1.0), strucUsageP.AsInteger())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, strucUsageP.AsInteger(), "3*2.1", strucUsageP.Set(3 * 2.1), strucUsageP.AsInteger())
'String StorageType
Dim markP As Parameter = pLst.First(Function(p) p.Definition.Name = "Mark")
str += vbLf & "String StorageType:" & vbLf
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, markP.AsString(), "2", markP.Set(2), markP.AsString())
str += String.Format("Before set:{0} " & vbTab & vbTab & "To:{1} " & vbTab & "Ret:{2} " & vbTab & "After set:{3}" & vbLf, markP.AsString(), """3.1""", markP.Set("3.1"), markP.AsString())
MessageBox.Show(str, "Parameter Set Signatures and Results")
Some information like the following may be outputted:
The results are not as expected or documented, are they? For a Double StorageType Parameter, its Set method can accept an INTEGER argument! For an Integer StorageType Parameter, its Set method accepts a double value, 1.0!
The trickiest part is the return values in all these cases are all TRUE!
It is good that the Parameter.Set() method offers some flexibility but at the same time it brings confusion. Similar situation is with the SetValueString() method.
The following might not make much sense but they do make things clearer:
SetElementId(ElementId)
SetDouble(Double)
SetInteger(Int32)
SetString(String)
If the flexibility has higher priority, a method like the following is obviously better:
Public Shared Sub SetParameterValue(ByVal p As Parameter, ByVal value As Object)
Try
If value.GetType().Equals(GetType(String)) Then
If p.SetValueString(TryCast(value, String)) Then
Return
End If
End If
Select Case p.StorageType
Case StorageType.None
Exit Select
Case StorageType.Double
If value.GetType().Equals(GetType(String)) Then
p.Set(Double.Parse(TryCast(value, String)))
Else
p.Set(Convert.ToDouble(value))
End If
Exit Select
Case StorageType.Integer
If value.GetType().Equals(GetType(String)) Then
p.Set(Integer.Parse(TryCast(value, String)))
Else
p.Set(Convert.ToInt32(value))
End If
Exit Select
Case StorageType.ElementId
If value.GetType().Equals(GetType(Autodesk.Revit.DB.ElementId)) Then
p.Set(TryCast(value, Autodesk.Revit.DB.ElementId))
ElseIf value.GetType().Equals(GetType(String)) Then
p.Set(New Autodesk.Revit.DB.ElementId(Integer.Parse(TryCast(value, String))))
Else
p.Set(New Autodesk.Revit.DB.ElementId(Convert.ToInt32(value)))
End If
Exit Select
Case StorageType.String
p.Set(value.ToString())
Exit Select
End Select
Catch
Throw New Exception("Invalid Value Input!")
End Try
End Sub
Revit Parameter Organizer can organize various Revit parameters such as Shared Parameters, Family Parameters, Project Parameters and Built-in Parameter in many good ways.
All possible good values will be accepted and the best intelligence can be achieved. The following code can be used to exercise the help method:
Dim wall As Wall = SelectWall(cmdData.Application.ActiveUIDocument.Selection)
Dim pLst As List(Of Parameter) = (From p In wall.Parameters Select p)
'Double StorageType
Dim baseOffsetP As Parameter = pLst.First(Function(p) p.Definition.Name = "Base Offset")
SetParameterValue(baseOffsetP, "2'3""")
SetParameterValue(baseOffsetP, "15")
SetParameterValue(baseOffsetP, "14.7")
SetParameterValue(baseOffsetP, 11)
SetParameterValue(baseOffsetP, 7.1)
Try
SetParameterValue(baseOffsetP, "abc")
Catch e As Exception
MessageBox.Show(e.Message)
End Try
'Integer StorageType
Dim strucUsageP As Parameter = pLst.First(Function(p) p.Definition.Name = "Structural Usage")
SetParameterValue(strucUsageP, "2")
SetParameterValue(strucUsageP, 1.0)
SetParameterValue(strucUsageP, 2L)
SetParameterValue(strucUsageP, 0)
Try
SetParameterValue(strucUsageP, wall)
Catch e As Exception
MessageBox.Show(e.Message)
End Try
'String StorageType
Dim markP As Parameter = pLst.First(Function(p) p.Definition.Name = "Mark")
SetParameterValue(markP, "Test by Spiderinnet")
SetParameterValue(markP, 123456.789)
SetParameterValue(markP, 2L)
SetParameterValue(markP, wall)
Try
SetParameterValue(markP, Nothing)
Catch e As Exception
MessageBox.Show(e.Message)
End Try
If an extension method for the Parameter class seems better, here it is:
#Region "Namespaces"
Imports System.Text
Imports System.Linq
Imports System.Xml
Imports System.Reflection
Imports System.ComponentModel
Imports System.Collections
Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Media.Imaging
Imports System.Windows.Forms
Imports System.IO
Imports Autodesk.Revit.ApplicationServices
Imports Autodesk.Revit.Attributes
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.DB.Events
Imports Autodesk.Revit.DB.Architecture
Imports Autodesk.Revit.DB.Structure
Imports Autodesk.Revit.DB.Mechanical
Imports Autodesk.Revit.DB.Electrical
Imports Autodesk.Revit.DB.Plumbing
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.UI.Selection
Imports Autodesk.Revit.UI.Events
Imports Autodesk.Revit.Collections
Imports Autodesk.Revit.Exceptions
Imports Autodesk.Revit.Utility
Imports RvtApplication = Autodesk.Revit.ApplicationServices.Application
Imports RvtDocument = Autodesk.Revit.DB.Document
#End Region
Namespace RevitAddinCS
Module ParameterExtension
<System.Runtime.CompilerServices.Extension()> _
Public Sub SetValue(ByVal p As Parameter, ByVal value As Object)
Try
If value.GetType().Equals(GetType(String)) Then
If p.SetValueString(TryCast(value, String)) Then
Return
End If
End If
Select Case p.StorageType
Case StorageType.None
Exit Select
Case StorageType.Double
If value.GetType().Equals(GetType(String)) Then
p.Set(Double.Parse(TryCast(value, String)))
Else
p.Set(Convert.ToDouble(value))
End If
Exit Select
Case StorageType.Integer
If value.GetType().Equals(GetType(String)) Then
p.Set(Integer.Parse(TryCast(value, String)))
Else
p.Set(Convert.ToInt32(value))
End If
Exit Select
Case StorageType.ElementId
If value.GetType().Equals(GetType(Autodesk.Revit.DB.ElementId)) Then
p.Set(TryCast(value, Autodesk.Revit.DB.ElementId))
ElseIf value.GetType().Equals(GetType(String)) Then
p.Set(New Autodesk.Revit.DB.ElementId(Integer.Parse(TryCast(value, String))))
Else
p.Set(New Autodesk.Revit.DB.ElementId(Convert.ToInt32(value)))
End If
Exit Select
Case StorageType.String
p.Set(value.ToString())
Exit Select
End Select
Catch
Throw New Exception("Invalid Value Input!")
End Try
End Sub
End Module
End Namespace
And the following code can be used to exercise the extension method:
Dim wall1 As Wall = SelectWall(cmdData.Application.ActiveUIDocument.Selection)
Dim pLst1 As List(Of Parameter) = (From p In wall1.Parameters Select p)
'Double StorageType
Dim baseOffsetP1 As Parameter = pLst1.First(Function(p) p.Definition.Name = "Base Offset")
baseOffsetP1.SetValue("2'3""")
baseOffsetP1.SetValue("15")
baseOffsetP1.SetValue("14.7")
baseOffsetP1.SetValue(11)
baseOffsetP1.SetValue(7.1)
Try
baseOffsetP1.SetValue("abc")
Catch e As Exception
MessageBox.Show(e.Message)
End Try
'Integer StorageType
Dim strucUsageP1 As Parameter = pLst1.First(Function(p) p.Definition.Name = "Structural Usage")
strucUsageP1.SetValue("2")
strucUsageP1.SetValue(1.0)
strucUsageP1.SetValue(2L)
strucUsageP1.SetValue(0)
Try
strucUsageP1.SetValue(wall)
Catch e As Exception
MessageBox.Show(e.Message)
End Try
'String StorageType
Dim markP1 As Parameter = pLst1.First(Function(p) p.Definition.Name = "Mark")
markP1.SetValue("Test by Spiderinnet")
markP1.SetValue(123456.789)
markP1.SetValue(2L)
markP1.SetValue(wall)
Try
markP1.SetValue(Nothing)
Catch e As Exception
MessageBox.Show(e.Message)
End Try
By the way, please do not forget to import the namespace of the module into the source that the above test code is in. For example, if the root namespace of the VB.NET project is RevitAddinVB_Test, please add the following line to the top of the source:
Imports RevitAddinVB_Test.RevitAddinCS.ParameterExtension
Parameter Writer of RevitAddinWizard will provide the intelligence in no time in C# or VB.NET depending on which language the current Visual Studio project is in.
Recent Comments