As a follow-on from the last post, today we’re going to see how to actually stop the erase operation from happening for a certain type of object (in this case we’re going to focus on Lines). Thanks for Stephen Preston for showing us the way in his comment on that post: inspired by his suggestion I ended up coding this before breakfast (although I do recommend taking care when throwing exceptions on an empty stomach ;-).
Here’s the C# code implementing the PER (Prevent Erasure) command:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace WeLikeToBlock
{
public class Commands
{
public class EraseOverrule : ObjectOverrule
{
public override void Erase(DBObject dbObject, bool erasing)
{
base.Erase(dbObject, erasing);
throw new
Autodesk.AutoCAD.Runtime.Exception(
ErrorStatus.NotApplicable
);
}
}
static EraseOverrule _theOverrule = null;
[CommandMethod("PER")]
static public void PreventErase()
{
Editor ed =
Application.DocumentManager.MdiActiveDocument.Editor;
if (_theOverrule == null)
{
_theOverrule = new EraseOverrule();
ObjectOverrule.AddOverrule(
RXObject.GetClass(typeof(Line)),
_theOverrule,
false
);
ObjectOverrule.Overruling = true;
ed.WriteMessage("\nPreventing erasure of lines.");
}
else
{
ObjectOverrule.RemoveOverrule(
RXObject.GetClass(typeof(Line)),
_theOverrule
);
_theOverrule.Dispose();
_theOverrule = null;
ed.WriteMessage("\nNo longer preventing erasure of lines.");
}
}
}
}
The original reason I started investigating this topic was a discussion group post where someone was trying to stop certain blocks from being redefined. Based on the approach of throwing exceptions, I revisited the idea of blocking certain block table records from being opened for write. While it stopped the redefinition from happening, it did (unsurprisingly) cause AutoCAD to crash, which is also why such a technique – while powerful – should be used with extreme caution (hence my comment in the last post describing the act of blocking Erase as being contentious or potentially disastrous). Certain code paths may not be ready for low-level operations within AutoCAD being blocked arbitrarily, especially operations such as opening symbol table records.
There may yet be a simple way to stop block redefinition – if I end up finding a way, I’ll certainly post it here.
Update:
I’ve just seen an internal thread discussing a scenario where blocking erase by throwing ErrorStatus.NotApplicable caused issues with undo. I haven’t been able to reproduce the problem, but I did want to post the solution in case it proves to be of help: in this situation returning ErrorStatus.CannotBeErasedByCaller did the trick.