I tried searching topics about shared parameters and found out that most of them are “create and add to project” my question is how about removing or deleting unused shared parameters? I’ve experienced working with the project that has the same parameter names. Any idea on how to sort parameter that has no value or just a duplicate?
@interactiverendering I was searching and was about to create the same topic but found this. Any update as to a solution?
Element.Parameters yields little distinguishable info to determine is used or not.
I believe it would be a wicked problem to solve, as how does one tell if a shared parameter is not being used? A parameter such as a boolean could be on/off for example - is it not in use if it is off?
The only method I can think of is it to collect all elements, use ‘get parameter value’ and ensure there are no filled versions of the parameter. Then the user would need to elect if it is safe to remove. It seems too risky otherwise.
Old topic, I know. regarding this, I would like to know how I can filter out allready deleted shared parameters? Actually, if you delete them manually in revit, you will still find them with with Dynamo, there is a ton of duplicates. Would be nice if I could filter all the “deleted” shared parameters.
I had a similar situation.
I’ve imported a few families into my project, than, after a few months deleted (replaced with family parameters) their shared parameters.
I actually used @GavC’s Crumple package for that (and Orchid)
So i improvised, and exported all the parameters from that family (now when they are family parameters) and added them to a new script to delete the shared parameters in project:
@interactiverendering you can remove the parameters like this too, but you will probably need to write them down one by one by hand. if you don’t know their origin family
addendum:
You can create a Multiple Category Schedule, export it, and then open it with Excel.
Then copy the second row into Notepad++
Format the text as a list for dynamo (helpful: Notepad++ add to every line - Stack Overflow)
and run the above script
So each one of those IDs must be deleted (search by IDs, then press DELETE). What we need is Autodesk to purge those after they have been removed from project parameters on a purge. Ideally after deleting the project parameters. It seems like a BUG IMO-
If the DYN were to delete any parameters that weren’t associated with andy project items or families- that would be it. But is that possible?
Not sure I follow what you’re after. Can you post an RVT in a new thread (linking here) with a data set to test on? Keep it to one unused shared parameter and one used shared parameter so we can confirm an initial POC.
Not too long ago I had a similar issue and I found that if I just iterated all ParamerElements and did a string equality on the param name I could then delete both and the Shared param would be gone. Now, that doesn’t check usage, but it was much faster than hunting ids in lookup.
This is because behind the scenes the binding remains. I believe amongst other reasons this relates to a parameter being able to remain in project schedules as a field post deletion. A good proof for this is;
Add a shared project parameter
Detele it from the model
In the shared param file, change its name but not its guid (bad I know)
Add it again
Its name will still be the old one. The model remembers it despite it being deleted. As you found the only way to get rid of them is targetting that Id behind the scenes.
Quick point of clarity - it’s not the bindings that remain, but the definition (which is defined by the shared parameter, which is defined by the GUID not the name). I believe that this is to prevent family data loss as the family elements may still need this data point to not go crazy if you do something like save out the family.
The code above (behind a spoiler as I’d qualify this as “dangerous to the point of not being recommended for for production”) should allow purging the definitions (via the shared parameter elements) if they are not in the bindings map (project parameters).
Hi,
an example solution with Python (only for instance parameters project), using the HasValue property
import sys
import clr
import System
from System.Collections.Generic import List
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# Force close any open transactions to ensure a clean slate
TransactionManager.Instance.ForceCloseTransaction()
# Get the parameter bindings of the document
bindingMap = doc.ParameterBindings
iterator = doc.ParameterBindings.ForwardIterator()
def_toRemove = []
result = []
while iterator.MoveNext():
definition = iterator.Key
binding = iterator.Current
if definition.IsValidObject:
if isinstance(binding, InstanceBinding):
categories = binding.Categories
# Create a filter to select elements in the categories of the binding
filterCats = ElementMulticategoryFilter(List[ElementId]([cat.Id for cat in categories]))
# Create a predicate to filter elements that have a value for the current parameter definition
filterByHasValue = System.Predicate[System.Object](lambda x : x.get_Parameter(definition) is not None and x.get_Parameter(definition).HasValue)
# Find all elements that have a null value for the current parameter definition
instanceNullValues = List[DB.Element](FilteredElementCollector(doc).WherePasses(filterCats).WhereElementIsNotElementType().ToElements()).FindAll(filterByHasValue)
if len(instanceNullValues) == 0:
def_toRemove.append(definition)
# Start a transaction to remove the parameter definitions
t = Transaction(doc, "Remove Parameters")
t.Start()
for def_ in def_toRemove:
#
if hasattr(def_, "Id"):
filterbyId = System.Predicate[System.Object](lambda x : x.Id == def_.Id)
# for all Parameters
#param_elem = List[DB.Element](FilteredElementCollector(doc).OfClass(ParameterElement).WhereElementIsNotElementType().ToElements()).Find(filterbyId)
# for only SharedParameters
param_elem = List[DB.Element](FilteredElementCollector(doc).OfClass(SharedParameterElement).WhereElementIsNotElementType().ToElements()).Find(filterbyId)
if param_elem is not None:
doc.Delete(param_elem.Id)
result.append("Project Parameter '{}' removed".format(def_.Name))
t.Commit()
t.Dispose()
OUT = result
import clr
# Import DocumentManager and TransactionManager
#https://forum.dynamobim.com/t/zombie-parameters-linger-after-delete-from-project-parameters/87934/4
#Jacob Small 2023-03-28
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
# Import relevant sections of the RevitAPI
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import Document, SharedParameterElement, FilteredElementCollector
doc = DocumentManager.Instance.CurrentDBDocument #the active document
TransactionManager.Instance.EnsureInTransaction(doc)# Start Transaction
FilterPrefix=IN[0]
FilterPrefix_ForcePurge=IN[1]
bindings = doc.ParameterBindings #get all the parameter bindings in the document
sharedParameters = FilteredElementCollector( doc ).OfClass(SharedParameterElement).ToElements() #get all shared parameters in the document
results = [] #an empty list for our results
for sp in sharedParameters: #for eveyr shared parameter perfor the following
spDef = sp.GetDefinition() #get the definition of the shared parameter
test = bindings.Contains(spDef) #test if the bindings map contains the defintion
name = sp.Name #get the name of the shared paramter
for Fpre in FilterPrefix: #For each prefix matching in list
ParamDelete = False
if name[:len(Fpre)]==Fpre: #Filter out prefixes
if not test: #if the definition was not in the bindings map
ParamDelete = True
results.append("--Deleted : {0}".format(name)) #let us know the parameter has been deleted
else:
results.append("___In Use : {0}".format(name)) #let us know the parameter is in use
if len(FilterPrefix_ForcePurge) > 0 : ##items in list
for FpreForce in FilterPrefix_ForcePurge :
if FpreForce>"" and name[:len(FpreForce)]==FpreForce:
ParamDelete = True
results.append("-DelForce : {0}".format(name)) #let us know the parameter has been deleted
if ParamDelete: ##Delete Parameters
ParamDelete = False
##doc.Delete(sp.Id) #delete the shared parameter
TransactionManager.Instance.TransactionTaskDone()# End Transaction
OUT = results #return the results to Dyanmo environment
and the Py.Dialog.Py:
#2023-Ron E. Allen simple form
import clr
import sys
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
import System
from System import Drawing
import System.Drawing
import System.Windows.Forms
from System.Drawing import *
from System.Windows.Forms import *
import math
##https://forum.dynamobim.com/t/reporting-to-user-at-the-end-of-dynamo-player-script/37421/6
from System.Windows.Forms import Form,Label,Button,FormBorderStyle,FormStartPosition
text="\r\n".join(IN[0]) #String each list item together with a return wrapline
#if IN[1] > 0 : ##Form Width input 1
fWide=IN[1] ##Use it
#else:
# fWide=int(400) ##Use default
#
#if IN[2] > 0 :
fHigh=IN[2] ##Form Height input 2
#else:
# fHigh=int(800) ##Use default
#
#if IN[3] > "" :
title=IN[3] ##Form Height input 2
#else:
# title="Result:"
#################################################################################
class popup(Form):
##
def __init__(self,text):
self.InitializeComponent(text)
def InitializeComponent(self,text):
#form = Form()
self.ClientSize = System.Drawing.Size(fWide, fHigh) ##Height
self.Text = title ##Form Title
self.FormBorderStyle = FormBorderStyle.FixedDialog ##Remove the maximize box.
self.MaximizeBox = False ## Set the MinimizeBox to false to remove the minimize box.
self.MinimizeBox = False ## Set the accept button of the form to button1.
self.StartPosition = FormStartPosition.CenterScreen
########Label for text#####
self.textbox = TextBox()
self.textbox.AutoScroll = True
self.textbox.ScrollBars = ScrollBars.Vertical
self.textbox.Parent = self
self.textbox.Text = text
##self.textbox.TextAlign = ContentAlignment.TopRight
self.textbox.Font = System.Drawing.Font("Tahoma", 8, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0)
self.textbox.Width = self.Width-20
self.textbox.Height = self.Height-50
self.textbox.Size = Size(self.Width-20, self.Height-50)
self.textbox.ReadRight = False
self.textbox.AutoSize = False
self.textbox.Multiline = True
##self.Controls.Add(self.label)
##self.Controls.Add(self.textbox)
##This was the key to wrapping hte text inside the lable on the form:
##https://stackoverflow.com/questions/1204804/word-wrap-for-a-label-in-windows-forms
#self.textbox.MaximumSize = System.Drawing.Size(self.Width-40,0)
self.textbox.WordWrap=True
self.textbox.Left=0
self.textbox.Top=0
self.ResumeLayout(False)
oForm=popup(text) ##Set the form with the text value
oForm.ShowDialog() ##Show the form
@dbrokaw - this is the script I thought might be tweaked for the “Schema” issues. If we delete out the schemas- they shoudl repopulate : )
You forgot about the ID of the parameter it should be deleted as well.
I saw this trick somewhere on the internet (not sure if its totally safe was mentioned)
Just copy the ID in the Revit warning, use Select by id in the (Revit)menu
Delete.
This delete the ID. Before the issue was deleting the parameter but the ID remained, preventing loading of an updated GUID of the same name… I.e. in cases where changing user modifiable, description, visibility… Has to be deleted. Then reloaded. This fixes that issue otherwise it complains the parameters are already defined.