I have an updater that will detect when rooms have been added or deleted to keep track of the counts, because the default count can't be used in formulas. I just tried adding a trigger for the room area so that when rooms are removed they are fully deleted so the user doesn't have to filter the schedule and delete it from there. The updater is triggered when I change the area with a room bounding line but, if I remove the room, the updater won't trigger even though the area changes to zero. Any thoughts on why that wouldn't work or how I might delete the rooms another way?
Solved! Go to Solution.
Solved by RPTHOMAS108. Go to Solution.
Are you using GetChangeTypeParameter? Not sure why that wouldn't work if the value was changing but the code example may help with that. There have been issues with other types of parameter not triggering in the past but in those cases they didn't trigger at all.
Here's the code for the trigger, I don't think I did anything weird other than put three changetypes in there. I originally just had two (addition and deletion) but after adding the parameter they still seem to trigger. I tried looking for another parameter to use, but the only one I could think of would have been location and I couldn't figure out what the id would be for that.
internal void AddTrigger()
{
UpdaterRegistry.AddTrigger(updaterid, new ElementCategoryFilter(BuiltInCategory.OST_Rooms),
ChangeType.ConcatenateChangeTypes(Element.GetChangeTypeElementAddition(), ChangeType.ConcatenateChangeTypes(Element.GetChangeTypeElementDeletion(), Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ROOM_AREA)))));
}
Hi AGilliam, I ran into this problem before, try changing the ElementCategoryFilter by an ElementCassFilter of a type SpatialElement : new ElementClassFilter(typeof(SpatialElement)).
your code will look like this.
internal void AddTrigger()
{
UpdaterRegistry.AddTrigger(updaterid,new ElementClassFilter(typeof(SpatialElement)),
ChangeType.ConcatenateChangeTypes(Element.GetChangeTypeElementAddition(), ChangeType.ConcatenateChangeTypes(Element.GetChangeTypeElementDeletion(), Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ROOM_AREA)))));
}
You should Adding the trigger three different times instead of concatenating the changeType.
internal void AddTrigger()
{
UpdaterRegistry.AddTrigger(updaterid,new ElementClassFilter(typeof(SpatialElement)),Element.GetChangeTypeElementAddition());
UpdaterRegistry.AddTrigger(updaterid,new ElementClassFilter(typeof(SpatialElement)),Element.GetChangeTypeElementDeletion());
UpdaterRegistry.AddTrigger(updaterid,new ElementClassFilter(typeof(SpatialElement)),Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ROOM_AREA)));
}
I just remembered that GetChangeTypeAny exists so I decided to test that out and it's triggering when the room gets removed like I originally expected, but I still have no idea what's actually triggering it if the change in area didn't work. I don't like the idea of the updater triggering for every change though, so I'm open to other ideas.
Remarks section for Element.GetChangeTypeParameter in RevitAPI.chm:
"...Note: This change type will not trigger on newly created or deleted elements."
So I would try again adding the separate triggers (Added/Removed/Parameter Changed) with the category filter for Rooms. You could use the class filter with SpatialElement but that then also includes changes to Areas & Spaces. You can't use Room class with ElementClassFilter because the Room class isn't in 'Revit's native object model'.
If you simplify it to those three triggers and it still doesn't work then create a minimum reproducible case. Since Autodesk has never confirmed you shouldn't be using a category filter for this (that should not be the case).
In the RevitAPI.chm the UpdaterRegistry.AddTrigger method overloads that takes a Filter actually note under the remarks section:
"This method only works with CategoryFilter and ParameterFilter."
Which is odd since this Wall updater example uses an ElementClassFilter.
The first time you've mentioned 'unplaced' is just now.
Would suggest then you create a minimum reproducible case with only the GetChangeTypeParameter. The filter is still required in the AddTrigger method regardless.
The Area for rooms parameter is kind of an odd one since when unplaced it will display 'Not Enclosed' in the UI, in RevitLookup it notes 0. So I still assume a change from +ve to 0 should be picked up as a parameter change.
You're right, I've been saying removed up until this point, but unplaced is what I meant. Sorry if that wasn't clear. Just to re-iterate my original intent, I'm trying to fully delete rooms that have been removed/unplaced so I need to detect that change with the updater. I've pasted a portion of my code below:
class RegRoomTracker : IExternalApplication
{
RoomTracker updater = null;
public Result OnStartup(UIControlledApplication uiapp)
{
AddInId addinId = uiapp.ActiveAddInId;
updater = new RoomTracker(addinId);
updater.RegisterUpdater();
updater.AddTrigger();
return Result.Succeeded;
}
public Result OnShutdown(UIControlledApplication uiapp)
{
UpdaterRegistry.UnregisterUpdater(updater.GetUpdaterId());
return Result.Succeeded;
}
}
class RoomTracker : IUpdater
{
private UpdaterId updaterid;
internal RoomTracker(AddInId addinId)
{
updaterid = new UpdaterId(addinId, new Guid("5CCFA69E-03F3-46D6-875D-5BB6FEF59190"));
}
internal void RegisterUpdater()
{
if (!UpdaterRegistry.IsUpdaterRegistered(updaterid))
UpdaterRegistry.RegisterUpdater(this, true);
}
internal void AddTrigger()
{
UpdaterRegistry.AddTrigger(updaterid, new ElementCategoryFilter(BuiltInCategory.OST_Rooms), Element.GetChangeTypeElementAddition());
UpdaterRegistry.AddTrigger(updaterid, new ElementCategoryFilter(BuiltInCategory.OST_Rooms), Element.GetChangeTypeElementDeletion());
UpdaterRegistry.AddTrigger(updaterid, new ElementCategoryFilter(BuiltInCategory.OST_Rooms), Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ROOM_AREA)));
//UpdaterRegistry.AddTrigger(updaterid, new ElementClassFilter(typeof(SpatialElement)), Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ROOM_LEVEL_ID)));
//UpdaterRegistry.AddTrigger(updaterid, new ElementClassFilter(typeof(SpatialElement)), Element.GetChangeTypeAny());
}
#region IUpdater Members
public void Execute(UpdaterData data)
{
Document doc = data.GetDocument();
List<ElementId> added = data.GetAddedElementIds().ToList();
List<ElementId> deleted = data.GetDeletedElementIds().ToList();
List<ElementId> modified = data.GetModifiedElementIds().ToList();
// Delete removed rooms
foreach (ElementId id in modified)
{
Room rm = doc.GetElement(id) as Room;
if (rm.Area == 0)
doc.Delete(id);
}
}
public UpdaterId GetUpdaterId()
{
return updaterid;
}
public ChangePriority GetChangePriority()
{
return ChangePriority.Annotations;
}
public string GetUpdaterName()
{
return "SchemaUpdater";
}
public string GetAdditionalInformation()
{
return "";
}
}
Your code seems to work ok for me when I drag the room outside it's boundary to unplace it.
What Revit version are you using?
Yes a placed room needs a boundary so you unplace it by dragging it out or deleting part of the boundary.
Architects sometimes have a number of unplaced rooms populated with parameters defined in their project template which they then copy into the relevant room areas.
Rooms are kind of odd they don't follow type/instance relationship but if you delete their physical representation in the UI they still exist in the colour scheme and schedule etc. (they can be scheduled and deleted in UI). Probably Revit keeps hold of them to maintain the room data they hold.
It probably would have solved a lot of headaches if they just followed the type/instance dynamic i.e. things common for a type of room defined in the type and other things such as area in the instance of that type.
Are there any further info on this? By our experience it is possible to use multiple type of ElementFilters for the trigger, but also had serious issues because some of our more specific triggers caused irrecoverable model corruption. Since then we only use the officially allowed category and parameter filters, and never had such model crashes. It would be really good to know what is the official explanation for having such note.