.NET
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page
Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Before asking this, I have looked everywhere without success.
I have a title sheet which I want to prevent being erased if certain conditions are met.
My code is:-
Friend Sub ObjectErased(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.DatabaseServices.ObjectErasedEventArgs) Select Case e.DBObject.Id.ObjectClass.Name Case "AcDbBlockReference" Using tr As Transaction = AcadDoc.TransactionManager.StartTransaction() Dim blk As BlockReference = CType(e.DBObject, BlockReference) Dim ac As AttributeCollection = blk.AttributeCollection If ac.Count > 0 Then For Each ad As ObjectId In ac Dim ar As AttributeReference = ad.GetObject(OpenMode.ForRead) If ar.Tag ="NO" Then blk.UpgradeOpen() ' ensure opened for write blk.Erase(False) ' prevent deletion Exit For End If Next End If End Using End Select End Sub
I had hoped that blk.Erase(False) would prevent the deletion, but it doesn't.
Can someone explain what I am doing wrong?
I have since added a tr.commit before exit for - no difference
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
"Looked everywhere"?
How about the well-known blog "through-the-interface" of Kean Walmsley? Check out this post of his:
http://through-the-interface.typepad.com/through_t
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Looked at blog before and I felt it might be too dangerous (going into areas I didn't understand).
However had another look and it is starting to work.
Now I have:-
Public Overrides Sub [Erase](ByVal obj As DBObject, ByVal erasing As Boolean)
MyBase.[Erase](obj, erasing)
If TypeOf obj Is BlockReference Then
Dim blk As BlockReference = CType(obj, BlockReference)
Dim ac As AttributeCollection = blk.AttributeCollection
If ac.Count > 0 Then
For Each ad As ObjectId In ac
Dim ar As AttributeReference = ad.GetObject(OpenMode.ForRead)
If ar.Tag = "NO" Then
Throw New Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.Not Applicable)
Exit For
End If
Next
End If
End If
End Sub
End Classbut
Dim ar As AttributeReference = ad.GetObject(OpenMode.ForRead)
crashes AutoCad with message
FATAL ERROR: Unhandled Access Violation Reading 0x0000 Exception at ...
Thanks for pointer though
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Did the crash occur in debugging session or normal Acad session?
The solution of preventing entity being erased in Kean's code is good in normal Acad session, but it is not "debug-able", because the solution is to raise an exception to stop erasing. Custom code cannot catch and handle this exception, or the erase would not be stopped. Thus, if you run the code ini debugging session, Acad always crash at the line when the exception is thrown.
Since this is the way the API is implemented, I do not know if there is a way to around it. So, if you debug your code, you do not want to try erase the title block with your overrule loaded. On the other hand, you you do try to erase the title block and Acad crash at the line of throwing exception in the debugging session, then it is good thing: your code will work in normal Acad session!
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
As I said before the crash occured on the line
Dim ar As AttributeReference = ad.GetObject(OpenMode.ForRead)
not
Throw New Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NotApplicable)
I was in debug mode to see this.
If I am not in debug mode, AutoCad pauses for some time and then crashes.
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
OK. I think it is probably due to the fact that you called MyBase.Erase() first, then try to identify if the entity being erased is your iverrule target. At the time, the entity may have been already flagged as "erased" of "effectivelyErased", so you cannot open it anymore.
So, you could try to move the MyBase.Erase() right in front of "Throw New....".
However, I'd not place the logic of finding overrule target in overriden Erase(0 method. I'd override IsApplicable() to define my own overrule filter, so that only intended targeting entity (in your case, the title block) is subject the overrule. That is, the logic of identifying overrule target is in IsApplicable() method, actual logic to stop erasing is in Erase() method, which is as simple as 2 lines of code:
MyBase.Erase()
Throw New ....
shown as Kean's blog.
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
I don't think is is myBase.Erase
I use Overrides quite often and I put the myBase etc at the end of the Sub, which I then did here. It still crashed on the
Dim ar at attribute
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
I don't understand your answer.
I now added:-
Public Overrides Function IsApplicable(ByVal overruledSubject As Autodesk.AutoCAD.Runtime.RXObject) As Boolean
AcadEdt.WriteMessage(overruledSubject.ToString)
Return MyBase.IsApplicable(overruledSubject)
End FunctionBut it doesn't come here.
Can you also explain what the [..] mean in
Public Overrides Sub [Erase](ByVal obj As DBObject, ByVal erasing As Boolean)
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
You need a bit study on Overrule's filter. In your case, you want to define your own custon filter: only block reference with given name or with given attribute tag is subject to your ObjectOverrule (cannot be erased).
I put together some quick code here:
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
namespace StopBlockErasing
{
public class NonErasableBlockOverule : ObjectOverrule
{
private bool _originalOverruling;
private List<string> _blockNames;
public NonErasableBlockOverule()
{
//Get a block name list from settiings
_blockNames = new List<string>();
_blockNames.AddRange(
new string[] { "Block1", "Block2", "Block3" }
);
}
public void StartOverruling()
{
//Save current overruling status (on/off)
_originalOverruling = Overrule.Overruling;
this.SetCustomFilter();
//Add this overule
Overrule.AddOverrule(RXObject.GetClass(typeof(Bloc kReference)), this, true);
Overrule.Overruling = true;
}
public void StopOverruling()
{
Overrule.RemoveOverrule(RXObject.GetClass(typeof(B lockReference)), this);
//Restore original overruling status
Overrule.Overruling = _originalOverruling;
}
//Implement overrule custom filter: only blockreference with
//give name is applicable
public override bool IsApplicable(RXObject overruledSubject)
{
BlockReference bref = overruledSubject as BlockReference;
if (bref == null) return false;
return IsTargetBlock(bref.Name);
}
public override void Erase(DBObject dbObject, bool erasing)
{
base.Erase(dbObject, erasing);
throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.Not Applicable);
}
#region private methods
private bool IsTargetBlock(string blkName)
{
foreach (string b in _blockNames)
{
if (b.ToUpper() == blkName.ToUpper()) return true;
}
return false;
}
#endregion
//------------------------------------------------ ------------
// Another version of IsApplication() implementing
// If a given attribute tag presents in the block
//------------------------------------------------ ------------
//public override bool IsApplicable(RXObject overruledSubject)
//{
// BlockReference bref = overruledSubject as BlockReference;
// if (bref == null) return false;
// //if we need to go through attribute to determine
// //whether the block should be erased or not
// if (bref.AttributeCollection.Count == 0) return false;
// Database db = bref.Database;
// using (Transaction tran = db.TransactionManager.StartTransaction())
// {
// foreach (ObjectId id in bref.AttributeCollection)
// {
// AttributeReference aref = tran.GetObject(
// id, OpenMode.ForRead) as AttributeReference;
// if (aref != null)
// {
// //Only remove a block, if one of its attribute tag is "AAA"
// if (aref.Tag.ToUpper() == "AAA") return true;
// }
// }
// }
// return false;
//}
}
}Here is the code to run it:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
[assembly: CommandClass(typeof(StopBlockErasing.MyCommands))]
namespace StopBlockErasing
{
class MyCommands
{
private static bool _blockOverruling = false;
private static NonErasableBlockOverule _myOverrule=null;
[CommandMethod("BlkOverrule")]
public static void MyCmd()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.D ocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
if (_myOverrule == null) _myOverrule = new NonErasableBlockOverule();
if (_blockOverruling)
{
_myOverrule.StopOverruling();
_blockOverruling=false;
ed.WriteMessage("\nNonErasableBlock Overrule is turned off.\n");
}
else
{
_myOverrule.StartOverruling();
_blockOverruling = true;
ed.WriteMessage("\nNonErasableBlock Overrule is turned on.\n");
}
}
}
}The code is in C#, but I think it would be easy to figure its VB.NET equivalent easily.
The IsApplicable is implemented this way: as long as the block name is "Block1", Block2" or "Block3", then the block cannot be erased. The extra IsApplicable() being commented out at the bottom is to check if a block has an attribute with Tag named as "AAA", if yes, the block is not erasable.
Notice the line:
this.SetCustomFilter();
You must call this method in order to tell Overrule to use your overriden IsApplicable() as custom filter.
I did run the code with my Acad2012 successfully (of make some block not erasable).
HTH.
Re: Prevent erase
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Thankyou for what was clearly a lot of hard work. I keep getting errors when trying to convert to VB, and so I will do it manually. However looking at your code made me think a little more and I got the answer.
I changed the line
Dim ar As AttributeReference = CType(ad.GetObject(OpenMode.ForRead), AttributeReference)
to using the Transaction - tr
Dim ar As AttributeReference = CType(tr.GetObject(arId, OpenMode.ForRead), AttributeReference)
