Hello,
I am creating a macro that gets all seleced elements, deletes any zones in the selection, then creates a new zone and adds the spaces from the selection to it. The code that I thought would accomplish it is below. It compiles, but when I run it I get the error message below. Does someone know what is causing the error?
Thank you
public void GetSpacesAndCreateZone() { UIDocument uiDoc = this.ActiveUIDocument; Document doc = uiDoc.Document; //get phase and level from active view to be used for creating zone View activeView = this.ActiveUIDocument.Document.ActiveView; Parameter param = activeView.get_Parameter(BuiltInParameter.VIEW_PHASE); ElementId eID = param.Id; Phase phase = doc.GetElement(eID) as Phase; Level lev = activeView.Level; //space set to be added to the zone SpaceSet spcSet = new SpaceSet(); //selected elements SelElementSet selSet = uiDoc.Selection.Elements; foreach (Element e in selSet) { if (e is Space) { //Cast the element to a space Space s = e as Space; //insert space into spcSet spcSet.Insert(s); } else if (e is Zone) { ElementId znID = e.Id; doc.Delete(znID); } else { selSet.Remove(e); } } //create zone and add spaces using (Transaction t = new Transaction(doc,"Create Zone")) { t.Start(); Zone zn = this.ActiveUIDocument.Document.Create.NewZone(lev, phase); zn.AddSpaces(spcSet); t.Commit(); } }
Solved! Go to Solution.
Solved by arnostlobel. Go to Solution.
Solved by arnostlobel. Go to Solution.
Solved by arnostlobel. Go to Solution.
You need to wrap the zone deletion code in a Transaction too,
else if (e is Zone) { ElementId znID = e.Id; doc.Delete(znID); }
I don't think anything else (aside from the part already wrapped in a Transaction) requires one.
I tried wrapping the zone deletion in a transaction. That portion of the macro works. Zones get deleted, but no new zone gets created and I still get the same error message. Does if maybe have something to do with the way I'm trying to create a zone, or getting the phase used for creating the zone? Here is the modified code that now wraps the zone deletion in a transaction:
public void GetSpacesAndCreateZone() { UIDocument uiDoc = this.ActiveUIDocument; Document doc = uiDoc.Document; //get phase and level from active view to be used for creating zone View activeView = this.ActiveUIDocument.Document.ActiveView; Parameter param = activeView.get_Parameter(BuiltInParameter.VIEW_PHASE); ElementId eID = param.Id; Phase phase = doc.GetElement(eID) as Phase; Level lev = activeView.Level; //space set to be used to create the zone SpaceSet spcSet = new SpaceSet(); //selected elements SelElementSet selSet = uiDoc.Selection.Elements; foreach (Element e in selSet) { if (e is Space) { //Cast the element to a space Space s = e as Space; //insert space into spcSet spcSet.Insert(s); } else if (e is Zone) { //delete the zone using (Transaction delZn = new Transaction(doc,"Delete Zone")) { delZn.Start(); ElementId znID = e.Id; doc.Delete(znID); delZn.Commit(); } } else { selSet.Remove(e); } }
//create zone and add spaces
using (Transaction newZnTran = new Transaction(doc,"New Zone"))
{
newZnTran.Start();
Zone zn = this.ActiveUIDocument.Document.Create.NewZone(lev, phase);
zn.AddSpaces(spcSet);
newZnTran.Commit();
}
}
My gess is that you are still getting the exception because modifying a selection object also requires a transaction. And because Revit throws when you attempt to do that the code never reaches the point at which you add the zone.
I suggest you modify the code the following way: Do not create several transactions, one for each operation. It is not a very efficient way of modifying a document, and it will also create too many undo items on the undo stack (visible in the undo menu). I recommend the following approach instead:
Thank you. Is there such a thing as a zone set that I could use to follow arnost's advice? If so, is there a way to find out on my own? I searched both Revit 2014 chm file and the api developers guide for "space set, "spcset", "zone set", "element set", and none of those searches found any kind of set.
For now, is it ok to start the transaction above the for loop and end it after the zone has been created? I tried it and it did not work. Here is the code and the error message it produced:
public void GetSpacesAndCreateZone() { UIDocument uiDoc = this.ActiveUIDocument; Document doc = uiDoc.Document; //get phase and level from active view to be used for creating zone View activeView = this.ActiveUIDocument.Document.ActiveView; Parameter param = activeView.get_Parameter(BuiltInParameter.VIEW_PHASE); ElementId eID = param.Id; Phase phase = doc.GetElement(eID) as Phase; Level lev = activeView.Level; //space set to be used to create the zone SpaceSet spcSet = new SpaceSet(); //selected elements SelElementSet selSet = uiDoc.Selection.Elements; //create zone and add spaces using (Transaction newZnTran = new Transaction(doc,"New Zone")) { newZnTran.Start(); foreach (Element e in selSet) { if (e is Space) { //Cast the element to a space Space s = e as Space; //insert space into spcSet spcSet.Insert(s); } else if (e is Zone) { ElementId znID = e.Id; doc.Delete(znID); } else { selSet.Remove(e); } } Zone zn = this.ActiveUIDocument.Document.Create.NewZone(lev, phase); zn.AddSpaces(spcSet); newZnTran.Commit(); } }
Hello Mcclanathan:
Yes, it is ok to keep it as you have it currently implemented. I generally recommend transactions to be as short-spanned as possible (hence my advice above), but since your command is expected to execute very fast without reaching to other modules and methods, it is all right to wrap the whole execution under one transaction.
To answer your question about the various sets: The SpaceSet and collections alike are an old kind of containers originated early in the Revit API of yesteryears. We do not use them anymore in newer API and we have been replacing them in the older API as well. Most of the methods in the current API now take (or return) regular .NET containers via generic interfaces, such as Ilist<>, ICollection<>, etc. For example, the Document.Delete method takes ICollection<ElementId>, which means you can use pretty much any standard .NET container.
Thank you for the advice. It is helpful. The macro still does not work. Does anyone have an idea why it is getting the error message above?
Try switching
ElementId eID = param.Id;
to
ElementId eID = param.AsElementId();
The way you have it now, you are retrieving the parameter, and trying to cast it as a Phase. The way I've shown it, you retrieve the value of the element ID stored in the parameter, which should represent the phase.
I haven't tested the code to see if it runs, but I don't see any more errors.
I switched to
ElementId eID = param.AsElementId();
and it still doesn't work. Does anyone see anything else the doesn't look right? Here is the error message:
Here is the code:
public void GetSpacesAndCreateZone() { UIDocument uiDoc = this.ActiveUIDocument; Document doc = uiDoc.Document; //get phase and level from active view to be used for creating zone View activeView = this.ActiveUIDocument.Document.ActiveView; Parameter param = activeView.get_Parameter(BuiltInParameter.VIEW_PHASE); ElementId eID = param.AsElementId(); Phase phase = doc.GetElement(eID) as Phase; Level lev = activeView.Level; //space set to be used to create the zone SpaceSet spcSet = new SpaceSet(); //selected elements SelElementSet selSet = uiDoc.Selection.Elements; //create zone and add spaces using (Transaction newZnTran = new Transaction(doc,"New Zone")) { newZnTran.Start(); foreach (Element e in selSet) { if (e is Space) { //Cast the element to a space Space s = e as Space; //insert space into spcSet spcSet.Insert(s); } else if (e is Zone) { ElementId znID = e.Id; doc.Delete(znID); } else { selSet.Remove(e); } } Zone zn = this.ActiveUIDocument.Document.Create.NewZone(lev, phase); zn.AddSpaces(spcSet); newZnTran.Commit(); } }
It would help if you could provide some info from debugging. The standard message Revit provides if an external command or macro fail (throws) is not always sufficient. If you could run your code in a debugger you'd be able to see at what line the exception is thrown, which would be a big help in narrowing down the problem.
My hunch is that you should probably remove the zone element you delete (in the foreach loop) from the selection too - and I mean before you delete it from the document. What the message is trying to tell you is that you (or you code, directly or indirectly) try to perform an operation on an object that no longer exist. And in this case, it could be the Selection object at the time you are removing from it, because it may still have references to zones you have already deleted (from the document).
Again, this is just a hunch. If you get to debug it you'd see what line exactly the problem raises at.
Cheers
I changed the recommened code, and still get the same error. Also, I figured out how to step into and debug. When I do that, the lev variable is null. Other than that, it steps all the way through and gets the error at the very end. Does anyone know why lev would be null in the following code?
Level lev = activeView.Level;
The is a floor plan with a group of zones selected when I run the macro.
I thouhgt that a floor plan requires a level? Is that not true? If not, can someone recommend the best way of getting the level it needs to apply the zones to?
Thank you
I got it to work. The isue was with getting the level from the view. The level property of the View is obsolete and was not getting the level of the view as I expected it to. I changed the level to GenLevel and it works. Here is the line of code I changed:
Level lev = activeView.GenLevel; //Originally it was: Level lev = activeView.Level;
Thanks for all the suggestions.
I got a new issue with the macro. I got it working on my laptop (which is a single user license in case that matters) as a macro, then I created an external command and got that working on my laptop as well. Then, I took the dll and and addin manifest and added the external command to my work computer (which is a network license), and I get the error message below. Does anyone know what might be causing this message?
Energygroup:
It looks like your code is removing from a selection set an element that does not exist anymore (was deleted).
Have you implemented all the modifications I sugested earlier?
Can you share the latest version of your code? (The external command Execute method?)
Thanks
Can't find what you're looking for? Ask the community or share your knowledge.