This guide aims to answer the question: how can I delete Sample Line Group
, or Sample Line
, or any other DBObject
from a Civil 3D drawing?
This could be necessary in the situation whereby you want to delete an existing outdated object, and replace it with an updated version, with the same Name
. Without properly deleting the object, you can’t create the same Name
object as Civil 3D will throw you the exception of cannot create XXX with duplicated name
exception.
The Erased()
method #
Let’s take Sample Line Group
as an example. But you can generalize this example to other entities pretty easily.
A Sample Line Group
contains a list of Sample Line
, via the GetSampleLineIds()
method. Usually, when we remove a Sample Line group
, we would also want to remove the list of Sample Line
because we expect that they all will be replaced with newer objects with exactly the same names. So, this is how you can delete all the entities cleanly, by using the Erase()
method
private void DeleteSampleLineGroup(SampleLineGroup sampleLineGroup, Transaction ts)
{
var sampleLineIds = sampleLineGroup.GetSampleLineIds();
foreach (ObjectId sampleLineId in sampleLineIds)
{
var sampleLine = (SampleLine)ts.GetObject(sampleLineId, OpenMode.ForWrite);
sampleLine.Erase();
}
sampleLineGroup.Erase();
}
Now, you can use the SampleLineGroup.Create
without problem.
Check for IsErased
Flag #
But this is not all! The gotcha is that when you are accessing the alignment.GetSampleLineGroupIds()
after you do the creation, you will have two instances of SampleLineGroup
, one deleted version, another newly created ones. Both have the same name. So how to differentiate them?
Here’s how, you use the ObjectId.IsErased==false
check.
private SampleLineGroup GetActiveSampleLineGroup(Alignment alignment,
Transaction ts, string selectedName)
{
var sectionLineGroup = alignment.GetSampleLineGroupIds(); // the list could contain two SampleLineGroup, but one of them is deleted.
foreach (ObjectId sampleLineGroupId in sectionLineGroup)
{
var sampleLineGroup = (SampleLineGroup)ts.GetObject
(sampleLineGroupId, OpenMode.ForWrite);
if ( sampleLineGroup.Name == selectedName&&
!sampleLineGroup.IsErased) //ensure that the erased one is filtered out
return sampleLineGroup;
}
throw new Exception("No active sample line group found");
}
Multiple Commits #
Alternatively, you can also commit the Transaction
. When you do the commit, the IsErased
object will be removed from the GetSampleLineGroupIds
or other equivalent methods.
/// <summary>
/// You need to commit first before you can see the changes
/// </summary>
[CommandMethod(nameof(MultipleCommitsToErase))]
public void MultipleCommitsToErase()
{
Transact(ts =>
{
var firstAlignmentId = CivilApplication.ActiveDocument.GetAlignmentIds()[0];
var alignment = ts.GetObject<Alignment>(firstAlignmentId, OpenMode.ForWrite);
var sampleLineGroupIds = alignment.GetSampleLineGroupIds();
var beforeCount = sampleLineGroupIds.Count; //assume 2
var sampleLineGroup = ts.GetObject<SampleLineGroup>(sampleLineGroupIds[0], OpenMode.ForWrite);
var sampleLineIds = sampleLineGroup.GetSampleLineIds();
foreach (ObjectId sampleLineId in sampleLineIds)
{
var sampleLine = ts.GetObject<SampleLine>(sampleLineId, OpenMode.ForWrite);
sampleLine.Erase();
}
sampleLineGroup.Erase();
var afterCount = alignment.GetSampleLineGroupIds().Count; //still the same Count, 2
});
Transact(ts =>
{
var firstAlignmentId = CivilApplication.ActiveDocument.GetAlignmentIds()[0];
var alignment = ts.GetObject<Alignment>(firstAlignmentId, OpenMode.ForWrite);
var sampleLineGroupIds = alignment.GetSampleLineGroupIds();
var theCount= sampleLineGroupIds.Count; // now it's 1;
//the Erased Object has been removed
});
}
public static T GetObject<T>(this Transaction ts, ObjectId objectId, OpenMode openMode = OpenMode.ForRead)
where T:DBObject
{
return ts.GetObject(objectId, openMode) as T;
}
private static void Transact(Action<Transaction> action)
{
var doc = Application.DocumentManager.MdiActiveDocument;
using var tr = doc.TransactionManager.StartTransaction();
action(tr);
tr.Commit();
}
As you can see, the count is only updated after you have Commit
the transaction, my guess is that Autodesk does this out of optimization purpose back in the early days of computing when every CPU cycle was expensive, so you don’t want to remove an Erased
object instantly. Instead you just mark it, and erase it at one go.