Hi everyone!
I am working on a code to remove unit symbols on all the selected schedule fields, by now my code is working well over the fields which are not configured to use default project settings, but for those ones using default project settings I am receiving this error:
" Exception : Autodesk.Revit.Exceptions.InvalidOperationException: UseDefault is true in this FormatOptions.
at Autodesk.Revit.DB.FormatOptions.GetUnitTypeId()
at Microsoft.Scripting.Interpreter.FuncCallInstruction`2.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run3[T0,T1,T2,TRet](T0 arg0, T1 arg1, T2 arg2)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope)
at Microsoft.Scripting.Hosting.ScriptSource.ExecuteAndWrap(ScriptScope scope, ObjectHandle& exception)"
If I manually deactivates the use project settings from the Revit UI the code works well, I would like to know if is possible to deactivate that option from the code, I thought the UseDefault property set to None would do this, but in this specific case it is not doing it, this is the code I am using:
ids = uidoc.Selection.GetElementIds()
for id in ids:
sched = doc.GetElement(id)
t = Transaction(doc, "Remove Unit Symbol")
t.Start()
#Get Schedule Definition
sched_def = sched.Definition
field_count = sched_def.GetFieldCount()
f_index = range(field_count)
#Itering over the schedule fields
for i in f_index:
field = sched_def.GetField(i)
field_name = field.GetName()
print (field_name)
#try:
# Get current FormatOptions from the field
format_options = field.GetFormatOptions()
unit_type_id = format_options.GetUnitTypeId()
accuracy = format_options.Accuracy
formatOpts = FormatOptions(unit_type_id)
formatOpts.UseDefault = False
formatOpts.Accuracy = accuracy
formatOpts.RoundingMethod.Nearest
field.SetFormatOptions(formatOpts)
print("Succesfully unit symbol removed")
#except:
#pass
#print("Error on unit setting")
t.Commit()
What I am doing wrong in my code?, I have attached an image for reference.
Thanks in advance!, greetings from Mexico city.
I asked the development team for you.
Hi Jeremy, Thanks so much!, I've clicked on the link in your answer but I can not access that site, please let me know if the development team provide some comments regarding this topic.
Hi @ggranadosNFAMX,
Could be a regeneration (of it's db) issue and you need a seperate transaction if the UseDefaults is changed?
First try if you can set the UseDefaults to false and don't call any edits after formatOpts.UseDefault = False
If it works then use a TransactionGroup to change all to UseDefault = False and then change the settings of the object.
Ps. The code can be optimized If you first check if UseDefault = False, and buffer those that are true.
- Michel
Yes, the link is internal, for my personal use, for cross-referencing.
The development team answers: Looks like the exception comes from an accessor on the default options. If you build the options with UseDefault = false and set it to the field, it should actually override successfully.
Hi @TripleM-Dev.net and @jeremy_tammik , thanks for your answers, I have tried to build the options with UseDefault = False, it seems to be working for the Length Field, but when it tries to change the velocity parameter it seems to fail when getting its unit type from the current format options, I have modified in the Revit UI the schedule to delete all fields except the Velocity one, and I see that the GetUnitTypeId method is retrieving a "meters" unit, so the exception " The display unit in formatOptions is not a valid display unit for the unit type of this ScheduleField" is happening.
This is my current code:
ids = uidoc.Selection.GetElementIds()
for id in ids:
sched = doc.GetElement(id)
#Get Schedule Definition
sched_def = sched.Definition
field_count = sched_def.GetFieldCount()
f_index = range(field_count)
#Itering over the schedule fields
for i in f_index:
# Get shedule fields
field = sched_def.GetField(i)
# Get field name
field_name = field.GetName()
print (field_name)
# Get current format options
format_options = field.GetFormatOptions()
# Changing UseDefault property to False
format_options.UseDefault = False
# Get field unit type
unit_type = format_options.GetUnitTypeId().TypeId
# Printing unit types for checking purpose
print (unit_type)
t = Transaction(doc, "Remove Unit Symbol")
t.Start()
# Setting the UseDefault to False
field.SetFormatOptions(format_options)
t.Commit()
# Printing UseDefault property to check
print (format_options.UseDefault)
it seems that when I change the UseDefault to false it automatically assign meters as the unit type?, honestly I am not sure how to use transaction groups, I'll take a look on that, maybe there is the key to get it working, Thank you for your time guys!.
Hi!, just an update on this, I still failing getting the GetUnitTypeId when the project default units are checked in the UI, it turned out that when I set the UseDefault property to False all the schedule fields they return meters automatically, so a workaround to solve this that worked for me by now, is to create a Dictionary with field names or headers as Key, and unit type ids and accuracy as Values, this way after set the UseDefault property to False, it can find the UnitTypeId directly in the Dictionary.
I think I could create a Dictionary including all the parameters I commonly use in the projects to be able to remove/set unit symbols in selected schedules.
This is the code that worked for me in this example:
var = {
"Flow" : [UnitTypeId.CubicFeetPerMinute,1],
"Area" : [UnitTypeId.SquareFeet, 0.01],
"Velocity" : [UnitTypeId.MetersPerSecond, 0.1],
"Length" : [UnitTypeId.Meters, 0.1],
"Friction" : [UnitTypeId.PascalsPerMeter, 0.1],
"Pressure Drop" : [UnitTypeId.Pascals, 0.01],
}
ids = uidoc.Selection.GetElementIds()
for id in ids:
sched = doc.GetElement(id)
t = Transaction(doc, "Remove Unit Sym")
t.Start()
#Get Schedule Definition
sched_def = sched.Definition
field_count = sched_def.GetFieldCount()
f_index = range(field_count)
#Itering over the schedule fields
for i in f_index:
field = sched_def.GetField(i)
field_name = field.GetName()
field_chead = field.ColumnHeading
print (field_chead)
#Removing unit symbol
for key in var:
unit = var[key][0]
accur = var[key][1]
#Removing unit symbold from fields
if field_chead == key:
try:
formatOpts = FormatOptions(unit)
formatOpts.UseDefault = False
formatOpts.Accuracy = accur
formatOpts.RoundingMethod.Nearest
field.SetFormatOptions(formatOpts)
print(key + " Succesfully unit symbol removed")
except:
pass
print(key + "Error on unit setting")
t.Commit()
Thanks!
I think the issue here you are setting a new reference to the format options. you need to get the formatoption from the feild it self, change usedefault = false, then set it back to the field.
this example works for me. it is in C# but i trust you can understand how it works
Trans.Start();
var schedule = UiDoc.ActiveGraphicalView as ViewSchedule;
for (int i = 0; i < schedule.Definition.GetFieldCount(); i++)
{
var field = schedule.Definition.GetField(i);
if(field.GetName()=="Height")
{
var form = field.GetFormatOptions();
form.UseDefault = false;
field.SetFormatOptions(form);
break;
}
}
Trans.Commit();
Hi @TripleM-Dev.net, Thanks for your answer, I tried to apply the solution using python, I think my code is doing the same as yours, But it is dealing with the same problem, for some reason for Set the format options back to the field, it is asking me for specify the UnitTypeId, and it throws the " The display unit in formatOptions is not a valid display unit for the unit type of this ScheduleField".
t = Transaction(doc, "Deactivate project default units")
t.Start()
ids = uidoc.Selection.GetElementIds()
for id in ids:
sched = doc.GetElement(id)
#Get Schedule Definition
sched_def = sched.Definition
field_count = sched_def.GetFieldCount()
f_index = range(field_count)
#Itering over the schedule fields
for i in f_index:
field = sched_def.GetField(i)
field_name = field.GetName()
print(field_name)
if field_name == "Pressure Drop":
format_options = field.GetFormatOptions()
format_options.UseDefault = False
field.SetFormatOptions(format_options)
t.Commit()
Do you see something that may be causing that in my python code?, Thanks again for your time!.
yep seems, when you set it to false, it doesn't pick one of the possible unit. you need to set the unit your self.
try using this line after setting to false
form.SetUnitTypeId(UnitTypeId.FeetOfWater39_2DegreesFahrenheit);
for the sake of more clarification
try on the UI and check the unit you need and apply it to the code
Thanks, @Moustafa_K. Specifying the unit as you suggested will work. In message 6, I mentioned that I am specifying the unit using dictionary keys and values. What I am trying to do is to get the current unit from the existing FormatOptions and use it to set new FormatOptions with the symbol units disabled.
The issue arises when I set the UseDefault property to False. This causes the GetUnitTypeId() method to automatically assign the meters unit to the FormatOptions. Consequently, the process stops because meters are not the appropriate unit for the fields in my selected schedule.
Therefore, I think using a dictionary or a CSV file with the units data is the solution for now.
Thanks again for your time!
Can't find what you're looking for? Ask the community or share your knowledge.