.NET下防止AutoCAD块被炸开

<Preventing an AutoCAD block from being exploded using .NET>


In response to these recent posts, I received a comment from Nick:

By any chance would it be possible to provide an example to prevent a user from using the EXPLODE command for a given block name?

I delved into the ADN knowledgebase and came across this helpful ObjectARX DevNote, which I used to create a .NET module to address the above question.

Here's the C# code, which should contain enough comments to make it self-explanatory:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;


namespace ExplosionPrevention

{

public class Commands

{

private Document _doc;

private Database _db;


private ObjectIdCollection _blkDefs =

   new ObjectIdCollection();

private ObjectIdCollection _blkRefs =

   new ObjectIdCollection();

private ObjectIdCollection _blkConts =

   new ObjectIdCollection();


private bool _handlers = false;

private bool _exploding = false;


[CommandMethod("STOPEX")]

public void StopBlockFromExploding()

{

   _doc =

      Application.DocumentManager.MdiActiveDocument;

   _db = _doc.Database;


   if (!_handlers)

   {

      AddEventHandlers();

      _handlers = true;

   }


   // Get the name of the block to protect


   PromptStringOptions pso =

      new PromptStringOptions(

      "\nEnter block name: "

      );

   pso.AllowSpaces = false;

   PromptResult pr =

      _doc.Editor.GetString(pso);


   if (pr.Status != PromptStatus.OK)

      return;


   Transaction tr =

      _db.TransactionManager.StartTransaction();

   using (tr)

   {

      // Make sure the block definition exists


      BlockTable bt =

      (BlockTable)

         tr.GetObject(

            _db.BlockTableId,

            OpenMode.ForRead

         );

      if (bt.Has(pr.StringResult))

      {

      // Collect information about the block...


      // 1. the block definition


      ObjectId blkId =

         bt[pr.StringResult];

      _blkDefs.Add(blkId);


      BlockTableRecord btr =

         (BlockTableRecord)

            tr.GetObject(

            blkId,

            OpenMode.ForRead

            );


      // 2. the block's contents


      foreach (ObjectId id in btr)

         _blkConts.Add(id);


      // 3. the block's references


      ObjectIdCollection blkRefs =

         btr.GetBlockReferenceIds(true, true);

      foreach (ObjectId id in blkRefs)

         _blkRefs.Add(id);

      }

      tr.Commit();

   }

}


private void AddEventHandlers()

{

   // When a block reference is added, we need to

   // check whether it's for a block we care about

   // and add it to the list, if so


   _db.ObjectAppended +=

      delegate(object sender, ObjectEventArgs e)

      {

      BlockReference br =

         e.DBObject as BlockReference;

      if (br != null)

      {

         if (_blkDefs.Contains(br.BlockTableRecord))

            _blkRefs.Add(br.ObjectId);

      }

      };


   // Conversely we need to remove block references

   // that as they're erased


   _db.ObjectErased +=

      delegate(object sender, ObjectErasedEventArgs e)

      {

      // This is called during as part of the cloning

      // process, so let's check that's not happening


      if (!_exploding)

      {

         BlockReference br =

            e.DBObject as BlockReference;

         if (br != null)

         {

            // If we're erasing, remove this block

            // reference from the list, otherwise if

            // we're unerasing we will want to add it

            // back in


            if (e.Erased)

            {

            if (_blkRefs.Contains(br.ObjectId))

               _blkRefs.Remove(br.ObjectId);

            }

            else

            {

            if (_blkDefs.Contains(br.BlockTableRecord))

               _blkRefs.Add(br.ObjectId);

            }

         }

      }

      };


   // This is where we fool AutoCAD into thinking the

   // block contents have already been cloned


   _db.BeginDeepClone +=

      delegate(object sender, IdMappingEventArgs e)

      {

      // Only for the explode context


      if (e.IdMapping.DeepCloneContext !=

            DeepCloneType.Explode)

         return;


      // We add IDs to the map to stop the

      // block contents from being cloned


      foreach (ObjectId id in _blkConts)

         e.IdMapping.Add(

            new IdPair(id, id, true, true, true)

         );

      };


   // And this is where we remove the mapping entries


   _db.BeginDeepCloneTranslation +=

      delegate(object sender, IdMappingEventArgs e)

      {

      // Only for the explode context


      if (e.IdMapping.DeepCloneContext !=

            DeepCloneType.Explode)

         return;


      // Set the flag for our CommandEnded handler


      _exploding = true;


      // Remove the entries we added on BeginDeepClone


      foreach (ObjectId id in _blkConts)

         e.IdMapping.Delete(id);

      };


   // As the command ends we unerase the block references


   _doc.CommandEnded +=

      delegate(object sender, CommandEventArgs e)

      {

      if (e.GlobalCommandName == "EXPLODE" && _exploding)

      {

         // By this point the block contents should not have

         // been cloned, but the blocks have been erased


         Transaction tr =

            _db.TransactionManager.StartTransaction();

         using (tr)

         {

            // So we need to unerase each of the erased

            // block references


            foreach (ObjectId id in _blkRefs)

            {

            DBObject obj =

               tr.GetObject(

                  id,

                  OpenMode.ForRead,

                  true

               );


            // Only unerase it if it's needed


            if (obj.IsErased)

            {

               obj.UpgradeOpen();

               obj.Erase(false);

            }

            }

            tr.Commit();

         }

         _exploding = false;

      }

      };

}

}

}

The STOPEX command takes a block name and then gathers (and stores) information about a block: its ObjectId, the IDs of its contents and its various block references. I've added some logic to handle creation of new block references (e.g. via INSERT), and erasure of ones that are no longer needed. I haven't put anything in to deal with redefinition of blocks (if the contents of blocks change then explosion may not be prevented properly), but this is left as an exercise for the reader

Let's define and insert a series of three blocks: LINES, ARCS and CIRCLES (no prizes for guessing which is which :-):

Inserted blocks

 

Now we run the STOPEX command on the LINES and CIRCLES blocks:

Command: STOPEX

Enter block name: circles

Command: STOPEX

Enter block name: lines

Command: EXPLODE

Select objects: all

9 found

Select objects:

Command: Specify opposite corner:

Selecting the "exploded" blocks, we see that only the ARCS blocks have actually been exploded:

Exploded blocks

 

转载于:https://www.cnblogs.com/jdmei520/articles/1512266.html

从acdbmgd.dll导出的内容,方便参考,格式如下: 类:Autodesk.AutoCAD.DatabaseServices.TextStyleTableRecord:Autodesk.AutoCAD.DatabaseServices.SymbolTableRecord New() 方法: {dtor}() {dtor}() {dtor}() {dtor}() ApplyPaperOrientationTransform(Viewport) ApplyPartialUndo(DwgFiler,RXClass) Audit(AuditInfo) Cancel() Close() CloseAndPage(Boolean) CopyFrom(RXObject) CreateExtensionDictionary() DisableUndoRecording(Boolean) Dispose() DowngradeOpen() DowngradeToNotify(Boolean) DwgIn(DwgFiler) DwgOut(DwgFiler) DxfIn(DxfFiler) DxfOut(DxfFiler) Erase() Erase(Boolean) HandOverTo(DBObject,Boolean,Boolean) ReleaseExtensionDictionary() RemoveField(ObjectId) ResetScaleDependentProperties() SetObjectIdsInFlux() SetPaperOrientation(Boolean) SwapIdWith(ObjectId,Boolean,Boolean) SwapReferences(IdMapping) UpgradeOpen() ViewportDraw(ViewportDraw) XDataTransformBy(Matrix3d) 函数: Clone() AS System.Object CompareTo(Object) AS System.Int32 CreateObjRef(Type) AS System.Runtime.Remoting.ObjRef DecomposeForSave(DwgVersion) AS Autodesk.AutoCAD.DatabaseServices.DecomposeForSaveReplacementRecord DeepClone(DBObject,IdMapping,Boolean) AS Autodesk.AutoCAD.DatabaseServices.DBObject Equals(Object) AS System.Boolean GetHashCode() AS System.Int32 GetLifetimeService() AS System.Object GetObjectSaveVersion(DwgFiler) AS Autodesk.AutoCAD.DatabaseServices.FullDwgVersion GetObjectSaveVersion(DxfFiler) AS Autodesk.AutoCAD.DatabaseServices.FullDwgVersion GetPersistentReactorIds() AS Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection GetReactors() AS System.Collections.Generic.List`1[[Autodesk.AutoCAD.Runtime.RXObject, acdbmgd, Version=17.1.0.0, Culture=neutral, PublicKeyToken=null]] GetRXClass() AS Autodesk.AutoCAD.Runtime.RXClass GetType() AS System.Type GetXDataForApplication(String) AS Autodesk.AutoCAD.DatabaseServices.ResultBuffer HasPersistentReactor(ObjectId) AS System.Boolean InitializeLifetimeService() AS System.Object QueryX(RXClass) AS System.IntPtr RemoveField() AS Autodesk.AutoCAD.DatabaseServices.ObjectId RemoveField(String) AS Autodesk.AutoCAD.DatabaseServices.ObjectId SetAttributes(DrawableTraits) AS System.Int32 SetField(Field) AS Autodesk.AutoCAD.DatabaseServices.ObjectId SetField(String,Field) AS Autodesk.AutoCAD.DatabaseServices.ObjectId SetFromStyle() AS System.Boolean ToString() AS System.String UpgradeFromNotify() AS System.Boolean ViewportDrawLogicalFlags(ViewportDraw) AS System.Int32 WblockClone(RXObject,IdMapping,Boolean) AS Autodesk.AutoCAD.DatabaseServices.DBObject WorldDraw(WorldDraw) AS System.Boolean X(RXClass) AS System.IntPtr 属性: AcadObject AS System.Object 可读不可写 Annotative AS Autodesk.AutoCAD.DatabaseServices.AnnotativeStates 可读可写 AutoDelete AS System.Boolean 可读可写 BigFontFileName AS System.String 可读可写 ClassID AS System.Guid 可读不可写 Database AS Autodesk.AutoCAD.DatabaseServices.Database 可读不可写 Drawable AS Autodesk.AutoCAD.GraphicsInterface.Drawable 可读不可写 DrawableType AS Autodesk.AutoCAD.GraphicsInterface.DrawableType 可读不可写 ExtensionDictionary AS Autodesk.AutoCAD.DatabaseServices.ObjectId 可读不可写 FileName AS System.String 可读可写 FlagBits AS System.Byte 可读可写 Font AS Autodesk.AutoCAD.GraphicsInterface.FontDescriptor 可读可写 Handle AS Autodesk.AutoCAD.DatabaseServices.Handle 可读不可写 HasFields AS System.Boolean 可读不可写 HasSaveVersionOverride AS System.Boolean 可读可写 Id AS Autodesk.AutoCAD.DatabaseServices.ObjectId 可读不可写 IsAProxy AS System.Boolean 可读不可写 IsCancelling AS System.Boolean 可读不可写 IsDependent AS System.Boolean 可读不可写 IsDisposed AS System.Boolean 可读不可写 IsErased AS System.Boolean 可读不可写 IsEraseStatusToggled AS System.Boolean 可读不可写 IsModified AS System.Boolean 可读不可写 IsModifiedGraphics AS System.Boolean 可读不可写 IsModifiedXData AS System.Boolean 可读不可写 IsNewObject AS System.Boolean 可读不可写 IsNotifyEnabled AS System.Boolean 可读不可写 IsNotifying AS System.Boolean 可读不可写 IsObjectIdsInFlux AS System.Boolean 可读不可写 IsPersistent AS System.Boolean 可读不可写 IsReadEnabled AS System.Boolean 可读不可写 IsReallyClosing AS System.Boolean 可读不可写 IsResolved AS System.Boolean 可读不可写 IsShapeFile AS System.Boolean 可读可写 IsTransactionResident AS System.Boolean 可读不可写 IsUndoing AS System.Boolean 可读不可写 IsVertical AS System.Boolean 可读可写 IsWriteEnabled AS System.Boolean 可读不可写 MergeStyle AS Autodesk.AutoCAD.DatabaseServices.DuplicateRecordCloning 可读可写 Name AS System.String 可读可写 ObjectBirthVersion AS Autodesk.AutoCAD.DatabaseServices.FullDwgVersion 可读不可写 ObjectId AS Autodesk.AutoCAD.DatabaseServices.ObjectId 可读不可写 ObliquingAngle AS System.Double 可读可写 OwnerId AS Autodesk.AutoCAD.DatabaseServices.ObjectId 可读可写 PaperOrientation AS Autodesk.AutoCAD.DatabaseServices.PaperOrientationStates 可读不可写 PriorSize AS System.Double 可读可写 TextSize AS System.Double 可读可写 UndoFiler AS Autodesk.AutoCAD.DatabaseServices.DwgFiler 可读不可写 UnmanagedObject AS System.IntPtr 可读不可写 XData AS Autodesk.AutoCAD.DatabaseServices.ResultBuffer 可读可写 XScale AS System.Double 可读可写 -------------------------------- 类:Autodesk.AutoCAD.DatabaseServices.TextVerticalMode:System.Enum 函数: CompareTo(Object) AS System.Int32 Equals(Object) AS System.Boolean GetHashCode() AS System.Int32 GetType() AS System.Type GetTypeCode() AS System.TypeCode ToString() AS System.String ToString(IFormatProvider) AS System.String ToString(String,IFormatProvider) AS System.String ToString(String) AS System.String 字段: TextBase AS TextVerticalMode TextBottom AS TextVerticalMode TextTop AS TextVerticalMode TextVerticalMid AS TextVerticalMode value__ AS Int32
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值