We have talked about getting information of shared parameters, attaching a shared parameter to some category instances, and creating new shared parameters. In this article, let’s see how to erase shared parameters with VB.NET or whether it is possible to achieve the goal programmatically with the in-box Revit APIs.
From checking on some relevant API classes and methods, it seems this is very achievable and in many ways. Firstly, the Definitions class or its parent DefinitionsBase has an Erase(Definition item) method which seems to do the right job; the Document.ParameterBindings property (actually the BindingMap class) has an Erase(Definition item) method too; and better it has another very similar method, Remove(Definition item), which seems to do the same job.
Let’s look at them one by one. The DefinitionsBase.Erase(Definition item) goes the first:
Public Shared Function RawConvertSetToList(Of T)(ByVal setVar As IEnumerable) As List(Of T)
Dim list As List(Of T) = (From p In setVar Select p)
Return list
End Function
Public Shared Function RawEraseSharedParameterDefinition(ByVal app As RvtApplication, ByVal name As String, ByVal group As String, ByVal type As ParameterType) As Boolean
Dim defFile As DefinitionFile = app.OpenSharedParameterFile()
If defFile IsNot Nothing Then
Dim dg As DefinitionGroup = RawConvertSetToList(Of DefinitionGroup)(defFile.Groups).FirstOrDefault(Function(g) g.Name = group)
If dg IsNot Nothing Then
Dim def As Definition = RawConvertSetToList(Of Definition)(dg.Definitions).FirstOrDefault(Function(d) d.Name = name)
If def IsNot Nothing AndAlso def.ParameterType = type Then
dg.Definitions.Erase(def)
Return True
End If
End If
End If
Return False
End Function
Use the following test code to exercise it:
…
RawEraseSharedParameterDefinition(CachedApp, "Volume41", "Group4", ParameterType.Volume)
…
However, out of most people’s expections, I believe, the following exception occurs:
Autodesk.Revit.Exceptions.InvalidOperationException: Collection is read-only
at Autodesk.Revit.DB.DefinitionsBase.Erase(Definition item)
Q: How come?
A: No idea!
So the first most natural way does not work at all!
Let’s try the second approach:
Public Shared Function RawEraseSharedParameterBinding1(ByVal app As RvtApplication, ByVal name As String, ByVal type As ParameterType) As Boolean
Dim map As BindingMap = (New UIApplication(app)).ActiveUIDocument.Document.ParameterBindings
Dim it As DefinitionBindingMapIterator = map.ForwardIterator()
it.Reset()
Dim def As Definition = Nothing
While it.MoveNext()
If it.Key IsNot Nothing AndAlso it.Key.Name = name AndAlso type = it.Key.ParameterType Then
def = it.Key
Exit While
End If
End While
If def IsNot Nothing Then
map.Erase(def)
End If
Return False
End Function
Use the following test code to exercise it:
…
RawEraseSharedParameterBinding1(CachedApp, "Volume41",ParameterType.Volume)
…
However another exception occurs:
Autodesk.Revit.Exceptions.InvalidOperationException at Autodesk.Revit.DB.BindingMap.Erase(Definition key)
Explanation: “The method Erase inherited from base class is not permitted for this class.”
Ok, now we have the last candidate left, the BindingMap.Remove(Definition key).
Public Shared Function RawEraseSharedParameterBinding2(ByVal app As RvtApplication, ByVal name As String, ByVal type As ParameterType) As Boolean
Dim map As BindingMap = (New UIApplication(app)).ActiveUIDocument.Document.ParameterBindings
Dim it As DefinitionBindingMapIterator = map.ForwardIterator()
it.Reset()
Dim def As Definition = Nothing
While it.MoveNext()
If it.Key IsNot Nothing AndAlso it.Key.Name = name AndAlso type = it.Key.ParameterType Then
def = it.Key
Exit While
End If
End While
If def IsNot Nothing Then
map.Remove(def)
End If
Return False
End Function
…
RawEraseSharedParameterBinding2(CachedApp, "Volume41",ParameterType.Volume)
…
No exception occurs this time, but readers may come up with some questions:
Q1. What does the method really do for us?
Q2. Why is the Definition from the DefinitionBinding always InternalDefiniton?
Q3. Will it also delete the shared parameter definition entry in the external DefinitionFile?
Q4. If the answer to the above is NO, how to do so programmatically?
A1: The method removes the parameter binding actually just as its name suggests. Or speak it another way, the purpose of the method is to remove a project parameter instead of a shared parameter. And it is model specific rather than application specific which can be seen from the place they come from. The ParameterBindings comes from a Revit Document but the DefinitionFile is associated with the Revit Application through its SharedParametersFilename property and can be retrieved directly through the OpenSharedParameterFile() method call.
Still confused? Don’t worry. We will get it finally.
Let’s try to explain a bit more and demonstrate with some concrete examples. If the shared parameter ‘Volume41’ is defined but not bound at all to any categories or not linked/converted to a project parameter, the above approach does nothing at all. If a non-shared and bound parameter (or call it ‘naked project parameter’ if we like) has the same name as the shared parameter of our real concern, the non-shared parameter will be mistakenly removed from the current model and from all related elements/categories, all existing data will be lost, and all affected schedules and tags will look different! That could be a disaster in the real design world. It also violates the safety rules that Revit tries to build up for us, removing shared parameters will not affect any existing data, elements, and models. If we delete shared parameters programmatically this way, it goes exactly onto the opposite way.
To make it clearer, here is a screenshot which shows some project parameters (or call them bound parameters if we like):
The first and the last ones are defined from shared parameters in the same sample ExternalFile that we addressed before. The middle three are real (or naked) project parameters. If you’d like to play around these a bit further, please rename any of the middle three as ‘Volume41’ with or without removing the last one, give the code one more try, and see what will be going on.
So the third approach is really to delete a Project Parameter or parameter DefinitionBinding rather than a shared parameter. Totally different things!
The first approach is the right one but it does not work!
A2: Not so sure. Maybe to tell us that bound shared parameters are the same as other project parameters now and do not behave as ‘shared parameters’ anymore.
A3: No, not at all.
A4: We will address it in another future post.
Revit Addin Coder of RevitAddinWizard can help address and clarify various parameter matters including built-in parameter, family parameter, shared parameter, project parameter and more in C# or VB.NET.
Hello, I have a question, whilst the last function does erase the Shared Parameter, Revit still seems to hold that GUID in there somewhere, meaning A) that Shared Parameter can never be renamed? and B) if by some freak occurrence another Shared Parameter is added with the same GUID them is will take on that name. Can the GUID/Shared Parameter be fully remove from Revit via .net?
Posted by: Christopher Mckeown | 04/04/2012 at 08:25 PM
You got the exact point!
This post is to actually address some possible ways using the in-box Revit API to erase shared parameters, but found the first two did not work at all. The last seemed to work but in fact did not either.
As you found out and was also discussed in the post, the BindingMap.Remove(Definition key) method is supposed to remove bound shared parameters (custom project parameters). It does not really remove the shared parameter from the share parameter definition file at all.
If we really want to erase the shared parameter definition so as to release its GUID and any resourdes it occupies, please refere to the next post:
Truly Erase Shared Parameter with VB.NET
http://spiderinnet.typepad.com/blog/2011/10/truly-erase-shared-parameter-with-vbnet.html
As talked about in that post, the Revit API does not provide a straightforward way to achieve the goal, but we can work around the limitation with out own way. And better the Shared Parameter Eraser coder of the Revit Addin Wizard can create the code for you in a second.
Posted by: Spiderinnet | 04/05/2012 at 01:14 AM
I am trying to find the RevitAddinWiazard all the links you have are broken. Am I doing something wrong?
Posted by: Cliffragan | 11/05/2012 at 03:02 PM
Some links were broken due to either removal of some old builds or changes to the google doc revision management. Sorry about that.
That explains why a central place was provided for the download link, which can be found at the bottom of the index page.
http://spiderinnet.typepad.com/blog/2011/05/revit-addin-wizardscoders-and-revit-api-widgets.html
Posted by: Spiderinnet | 11/05/2012 at 08:19 PM