Hello,
I'm creating a sort of "Property Editor" dialog for user selected elements. In my dialog, the user may pick from a list of non read-only parameters, and specify an alternate value that my application will use later on under particular circumstances (see dialog image below).
The challenge is to provide a list of relevant alternate "Element Id Values" based on the selected parameter. So far, my approach is to explicitly exam the "Current Value (ElementId)" of selected parameter and create alternate value list accordingly. For some "Current Values" I use the "GetSimilarTypes" function, while others I simply filter the document for elements of same category (see code below image).
So far I have two questions...
Thanks,
Jon
if (request == EditPropertyOptRequest.GetAvailableValues) {
cond.SelElemValue = null; cond.PropertyOpt.ElementValues = new ObservableCollection<Element>(); try { dynamic CurrentElem = doc.GetElement(cond.SelProperty.AsElementId); if ((CurrentElem) is WallType) { WallType obj = CurrentElem; foreach (void ElemId_loopVariable in obj.GetSimilarTypes) { ElemId = ElemId_loopVariable; cond.PropertyOpt.ElementValues.Add(doc.GetElement(ElemId)); } } else if ((CurrentElem) is FloorType) { FloorType obj = CurrentElem; foreach (void ElemId_loopVariable in obj.GetSimilarTypes) { ElemId = ElemId_loopVariable; cond.PropertyOpt.ElementValues.Add(doc.GetElement(ElemId)); } } else if ((CurrentElem) is FamilySymbol) { FamilySymbol obj = CurrentElem; foreach (void ElemId_loopVariable in obj.GetSimilarTypes) { ElemId = ElemId_loopVariable; cond.PropertyOpt.ElementValues.Add(doc.GetElement(ElemId)); } } else if ((CurrentElem) is Level) { FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType(); foreach (void elem_loopVariable in collector) { elem = elem_loopVariable; cond.PropertyOpt.ElementValues.Add(elem); } } else if ((CurrentElem) is Phase) { FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfCategory(BuiltInCategory.OST_Phases).WhereElementIsNotElementType(); foreach (void elem_loopVariable in collector) { elem = elem_loopVariable; cond.PropertyOpt.ElementValues.Add(elem); } } cond.SelElemValue = cond.PropertyOpt.ElementValues(0); } catch (Exception ex) { } }
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
Solved by FAIR59. Go to Solution.
Quick update...
After realizing "GetSimilarTypes" method is inherited from "ElementType" base class, I now attempt to cast Element to ElementType, then use "GetSimilarTypes" method if "ElemType" is Not NULL. Otherwise I filter document for NonElementTypes of same Category. I still need to handle elements with No Category, which so far I've identified Line Styles as being this way.
I am quite happy with this approach!
Jon
if (request == EditPropertyOptRequest.GetAvailableValues) { cond.SelElemValue = null; cond.PropertyOpt.ElementValues = new ObservableCollection<Element>(); if (cond.SelProperty.StorageType == StorageType.ElementId) { ElementId ElemId = cond.SelProperty.AsElementId; if (ElemId == null) return; Element Elem = doc.GetElement(ElemId); ElementType ElemType = Elem as ElementType; if (ElemType != null) { foreach ( ElemId in ElemType.GetSimilarTypes) { cond.PropertyOpt.ElementValues.Add(doc.GetElement(ElemId)); } } else if (Elem.Category != null) { FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfCategory(Elem.Category.Id.IntegerValue).WhereElementIsNotElementType(); foreach ( Elem in collector) { cond.PropertyOpt.ElementValues.Add(Elem); } } else { // //Handle non-category elements. Namely Line Styles(aka GraphicStlyes) // } cond.SelElemValue = cond.PropertyOpt.ElementValues(0); } }
Dear Jon,
Thank you for sharing this.
How does this fit in with the combo box dropdown workarounds suggested here?
http://thebuildingcoder.typepad.com/blog/2015/11/drop-down-enumerated-parameter-values.html
Should I add your solution as a new workaround, or is it a different class of animal?
Thank you!
Cheers,
Jeremy
Hi Jeremy,
I believe this is a "different class of animal". In brief, the post touches on how to mimic contextual content of Element Properties Panel using Revit API. More specifically, how to get a list of available ElementId values for a given Parameter whos Storage Type = ElementId and has an existing value to use as reference. Mostly revolving around use of 'ElementType.GetSimilarTypes' method.
Note: I still cant find a way to get available values for a Parameter that does not have existing value for reference.
Thanks,
Jon
Dear Jon,
Thank you, all clear now.
To get available values for a Parameter that does not have an existing value for reference, you might be able to create a suitable template element in a temporary transaction, grab the data you require from it, and roll back the transaction without committing, also know as the 'temporary transaction trick' TTT:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.53
Cheers,
Jeremy
Thanks for suggestion Jeremy,
TTT may work, but I don't see a way to determine what a "suitable template element" might be. Given a parameter with <null> ElementID value, the only helpful information looks like BuiltInParameter Id, but that doesn't get me very far. Worst case, I make exceptions for my favorite BuiltInParameter Id's to assist in determining "suitable template element".
Almost as if the Parameter class would benefit from something like a "GetSampleValueType" method.
Jon
you can use a ElementParameterFilter, to get all the elements that have a value other then ElementId.InvalidElementId for a specific parameter.
this code filters for elements in the active view, that are demolished in some phase.
ParameterValueProvider pvp_Demolished = new ParameterValueProvider(new ElementId((int)BuiltInParameter.PHASE_DEMOLISHED)); FilterNumericGreater fgreater = new FilterNumericGreater(); FilterElementIdRule IdFilter = new FilterElementIdRule(pvp_Demolished, fgreater, ElementId.InvalidElementId); ElementParameterFilter efilter = new ElementParameterFilter(IdFilter); FilteredElementCollector elems = new FilteredElementCollector(doc, doc.ActiveView.Id) .WherePasses(efilter);
Thanks for the suggestion FAIR59,
Unfortunately that's not what I'm looking to accomplish. Please see video below for better explanation of what I'm trying to do. Maybe you might have another idea.
Thanks,
Jon
Actually, it is part of what you are trying to accomplish. With an ElementParameterFilter you get a list of Elements (if there are any) that have a value for the parameter in question, and then you may find all the relevant values, or display all the found values.
Oh I see now, VERY CLEVER!!!
Just implemented and works like a charm. Only caveat like you say is "if there are any", but I can live with that.
Thanks for the great tip!!!
Jon
Rescued for posterity here:
Thanks guys, especially Fair59!
Cheers,
Jeremy
Can't find what you're looking for? Ask the community or share your knowledge.