将 ObjectIds 传递给方法似乎会破坏流程 - C# 中的 BURST 示例
Passing ObjectIds to method seems to break the process - BURST example in C#
我有一个模仿 BURST 命令的方法,但使用 AutoCAD 的 .NET 界面。 Select一个block,输入命令,没问题。但我想做的是将它变成一个可调用的方法,这样我就可以获得一组 ObjectIds、所有 BlockReferences,并让它一次一个地爆破它们。
我的 BURST 方法可以正常工作,并且可以证明每次调用方法时都是正确的 ObjectId。它在 .Explode 命令之后循环遍历收集到的块中的每个实体,但由于某种原因,该作品从未发布(回复:没有任何东西最终爆炸)。
我被卡住了,现在已经为此工作了几个小时,这显然超出了我的理解范围。我猜这是我忽略但看不到的一件小事。
// BURST command that bursts ALL blocks
[CommandMethod("testBurstAll")]
public void cmdTestBurstAll()
{
// Definitions
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
List<ObjectId> passedObjectId = new List<ObjectId>();
try
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
ObjectId oID = bt[BlockTableRecord.ModelSpace];
BlockTableRecord btr = tr.GetObject(oID, OpenMode.ForWrite) as BlockTableRecord;
//ed.WriteMessage("Made it to end of BT and BTR definitions");
RXClass rxBlockRef = RXClass.GetClass(typeof(BlockReference));
//ed.WriteMessage("Made it to RXClass definition");
foreach (ObjectId id in btr)
{
if (id.IsNull || id.IsErased || id.IsEffectivelyErased || !id.IsValid)
continue;
// get a list of ObjectIds for future method call
if (id.ObjectClass == rxBlockRef)
{
passedObjectId.Add(id);
ed.WriteMessage("\nOriginal method ObjectId: " + id.ToString());
/*using (BlockReference reference = tr.GetObject(id, OpenMode.ForWrite) as BlockReference)
{
ed.WriteMessage("Made it into explode");
//reference.ExplodeToOwnerSpace();
reference.Erase();
//ed.WriteMessage("Made it past explode");
}*/
}
}
// Call BURST method for each BlockReference ObjectId added to list
for( int i = 0; i < passedObjectId.Count; i++)
{
cmdTestBurstMethod(passedObjectId.ElementAt(i));
}
}
}
catch
{
ed.WriteMessage("CATCH used, exception caught");
}
}
// BURST method - to be called by other commands - needs an ObjectID as input
public void cmdTestBurstMethod(ObjectId passedId)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
//ed.WriteMessage("\nMade it into BURST method call with: " + passedId.ToString());
using (Transaction tr = db.TransactionManager.StartTransaction())
{
ObjectId msId = SymbolUtilityServices.GetBlockModelSpaceId(db);
BlockTableRecord ms = tr.GetObject(msId, OpenMode.ForWrite) as BlockTableRecord;
BlockReference blockRef = tr.GetObject(passedId, OpenMode.ForRead) as BlockReference;
ed.WriteMessage("\nInto BURST method with OjbectId: " + blockRef.ObjectId.ToString());
if (blockRef != null)
{
DBObjectCollection toAddColl = new DBObjectCollection();
BlockTableRecord blockDef = tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
// Create a text for const and visible attributes
foreach (ObjectId entId in blockDef)
{
if (entId.ObjectClass.Name == "AcDbAttributeDefinition")
{
AttributeDefinition attDef = tr.GetObject(entId, OpenMode.ForRead) as AttributeDefinition;
if ((attDef.Constant && !attDef.Invisible))
{
DBText text = new DBText();
text.Height = attDef.Height;
text.TextString = attDef.TextString;
text.Position = attDef.Position.TransformBy(blockRef.BlockTransform);
toAddColl.Add(text);
}
}
}
// Create a text for non-const and visible attributes
foreach (ObjectId attRefId in blockRef.AttributeCollection)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead) as AttributeReference;
if (attRef.Invisible == false)
{
DBText text = new DBText();
text.Height = attRef.Height;
text.TextString = attRef.TextString;
text.Position = attRef.Position;
toAddColl.Add(text);
}
}
// Get the entities from the block reference Attribute definitions have been taken care of.. so ignore them
DBObjectCollection entityColl = new DBObjectCollection();
blockRef.Explode(entityColl);
// Get Layer of existing Block and move any objects in that block to the existing layer of the Block (anything on layer '0')
ed.WriteMessage("\nblockRef NOT NULL");
String exLayer = blockRef.Layer;
foreach (Entity ent in entityColl)
{
ed.WriteMessage("\nForEach loop entered with: " + ent.ObjectId.ToString());
if (!(ent is AttributeDefinition))
{
ed.WriteMessage("\nEntered IF !AttributeDefinition");
if (ent.Layer == "0")
{
ed.WriteMessage("\nEntered IF on Layer zero");
ent.Layer = exLayer;
}
toAddColl.Add(ent);
}
}
// Add the entities to modelspace
foreach (Entity ent in toAddColl)
{
ms.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
}
// Erase the block reference
blockRef.UpgradeOpen();
blockRef.Erase();
}
tr.Commit();
}
}
没有展开任何内容,因为未提交父事务。
所以每个子事务都会回滚。
避免为每个 ObjectId 启动新的子事务的一种方法是将父事务作为参数传递。
然后在顶层方法中提交父事务,在突发之后。
这是一个简单粗暴的例子:
[CommandMethod("TEST")]
public static void Test()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
using (var tr = db.TransactionManager.StartTransaction())
{
var modelSpace = (BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
var brClass = RXObject.GetClass(typeof(BlockReference));
var ids = modelSpace
.Cast<ObjectId>()
.Where(id => id.ObjectClass == brClass);
foreach (ObjectId id in ids)
{
Burst(id, modelSpace, tr);
}
tr.Commit();
}
}
private static void Burst(ObjectId id, BlockTableRecord owner, Transaction tr)
{
var br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
foreach (ObjectId attId in br.AttributeCollection)
{
var attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);
CreateTextFromAttrib(attRef, br.Layer, owner, tr);
attRef.Erase();
}
var entities = new DBObjectCollection();
br.Explode(entities);
foreach (Entity entity in entities)
{
if (entity is AttributeDefinition)
{
var attDef = (AttributeDefinition)entity;
if (attDef.Constant)
{
CreateTextFromAttrib(attDef, br.Layer, owner, tr);
}
entity.Dispose();
}
else
{
if (entity.Layer == "0") entity.Layer = br.Layer;
if (entity.ColorIndex == 0) entity.ColorIndex = 256;
owner.AppendEntity(entity);
tr.AddNewlyCreatedDBObject(entity, true);
}
}
br.Erase();
}
private static void CreateTextFromAttrib(DBText att, string layer, BlockTableRecord owner, Transaction tr)
{
var text = new DBText
{
Rotation = att.Rotation,
TextString = att.TextString,
Height = att.Height,
Justify = att.Justify,
Position = att.Position
};
text.SetPropertiesFrom(att);
if (att.Justify != AttachmentPoint.BaseLeft)
{
text.AlignmentPoint = att.AlignmentPoint;
}
if (text.Layer == "0") text.Layer = layer;
if (text.ColorIndex == 0) text.ColorIndex = 256;
owner.AppendEntity(text);
tr.AddNewlyCreatedDBObject(text, true);
}
我有一个模仿 BURST 命令的方法,但使用 AutoCAD 的 .NET 界面。 Select一个block,输入命令,没问题。但我想做的是将它变成一个可调用的方法,这样我就可以获得一组 ObjectIds、所有 BlockReferences,并让它一次一个地爆破它们。
我的 BURST 方法可以正常工作,并且可以证明每次调用方法时都是正确的 ObjectId。它在 .Explode 命令之后循环遍历收集到的块中的每个实体,但由于某种原因,该作品从未发布(回复:没有任何东西最终爆炸)。
我被卡住了,现在已经为此工作了几个小时,这显然超出了我的理解范围。我猜这是我忽略但看不到的一件小事。
// BURST command that bursts ALL blocks
[CommandMethod("testBurstAll")]
public void cmdTestBurstAll()
{
// Definitions
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
List<ObjectId> passedObjectId = new List<ObjectId>();
try
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
ObjectId oID = bt[BlockTableRecord.ModelSpace];
BlockTableRecord btr = tr.GetObject(oID, OpenMode.ForWrite) as BlockTableRecord;
//ed.WriteMessage("Made it to end of BT and BTR definitions");
RXClass rxBlockRef = RXClass.GetClass(typeof(BlockReference));
//ed.WriteMessage("Made it to RXClass definition");
foreach (ObjectId id in btr)
{
if (id.IsNull || id.IsErased || id.IsEffectivelyErased || !id.IsValid)
continue;
// get a list of ObjectIds for future method call
if (id.ObjectClass == rxBlockRef)
{
passedObjectId.Add(id);
ed.WriteMessage("\nOriginal method ObjectId: " + id.ToString());
/*using (BlockReference reference = tr.GetObject(id, OpenMode.ForWrite) as BlockReference)
{
ed.WriteMessage("Made it into explode");
//reference.ExplodeToOwnerSpace();
reference.Erase();
//ed.WriteMessage("Made it past explode");
}*/
}
}
// Call BURST method for each BlockReference ObjectId added to list
for( int i = 0; i < passedObjectId.Count; i++)
{
cmdTestBurstMethod(passedObjectId.ElementAt(i));
}
}
}
catch
{
ed.WriteMessage("CATCH used, exception caught");
}
}
// BURST method - to be called by other commands - needs an ObjectID as input
public void cmdTestBurstMethod(ObjectId passedId)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
//ed.WriteMessage("\nMade it into BURST method call with: " + passedId.ToString());
using (Transaction tr = db.TransactionManager.StartTransaction())
{
ObjectId msId = SymbolUtilityServices.GetBlockModelSpaceId(db);
BlockTableRecord ms = tr.GetObject(msId, OpenMode.ForWrite) as BlockTableRecord;
BlockReference blockRef = tr.GetObject(passedId, OpenMode.ForRead) as BlockReference;
ed.WriteMessage("\nInto BURST method with OjbectId: " + blockRef.ObjectId.ToString());
if (blockRef != null)
{
DBObjectCollection toAddColl = new DBObjectCollection();
BlockTableRecord blockDef = tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
// Create a text for const and visible attributes
foreach (ObjectId entId in blockDef)
{
if (entId.ObjectClass.Name == "AcDbAttributeDefinition")
{
AttributeDefinition attDef = tr.GetObject(entId, OpenMode.ForRead) as AttributeDefinition;
if ((attDef.Constant && !attDef.Invisible))
{
DBText text = new DBText();
text.Height = attDef.Height;
text.TextString = attDef.TextString;
text.Position = attDef.Position.TransformBy(blockRef.BlockTransform);
toAddColl.Add(text);
}
}
}
// Create a text for non-const and visible attributes
foreach (ObjectId attRefId in blockRef.AttributeCollection)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead) as AttributeReference;
if (attRef.Invisible == false)
{
DBText text = new DBText();
text.Height = attRef.Height;
text.TextString = attRef.TextString;
text.Position = attRef.Position;
toAddColl.Add(text);
}
}
// Get the entities from the block reference Attribute definitions have been taken care of.. so ignore them
DBObjectCollection entityColl = new DBObjectCollection();
blockRef.Explode(entityColl);
// Get Layer of existing Block and move any objects in that block to the existing layer of the Block (anything on layer '0')
ed.WriteMessage("\nblockRef NOT NULL");
String exLayer = blockRef.Layer;
foreach (Entity ent in entityColl)
{
ed.WriteMessage("\nForEach loop entered with: " + ent.ObjectId.ToString());
if (!(ent is AttributeDefinition))
{
ed.WriteMessage("\nEntered IF !AttributeDefinition");
if (ent.Layer == "0")
{
ed.WriteMessage("\nEntered IF on Layer zero");
ent.Layer = exLayer;
}
toAddColl.Add(ent);
}
}
// Add the entities to modelspace
foreach (Entity ent in toAddColl)
{
ms.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
}
// Erase the block reference
blockRef.UpgradeOpen();
blockRef.Erase();
}
tr.Commit();
}
}
没有展开任何内容,因为未提交父事务。
所以每个子事务都会回滚。
避免为每个 ObjectId 启动新的子事务的一种方法是将父事务作为参数传递。
然后在顶层方法中提交父事务,在突发之后。
这是一个简单粗暴的例子:
[CommandMethod("TEST")]
public static void Test()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
using (var tr = db.TransactionManager.StartTransaction())
{
var modelSpace = (BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
var brClass = RXObject.GetClass(typeof(BlockReference));
var ids = modelSpace
.Cast<ObjectId>()
.Where(id => id.ObjectClass == brClass);
foreach (ObjectId id in ids)
{
Burst(id, modelSpace, tr);
}
tr.Commit();
}
}
private static void Burst(ObjectId id, BlockTableRecord owner, Transaction tr)
{
var br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
foreach (ObjectId attId in br.AttributeCollection)
{
var attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);
CreateTextFromAttrib(attRef, br.Layer, owner, tr);
attRef.Erase();
}
var entities = new DBObjectCollection();
br.Explode(entities);
foreach (Entity entity in entities)
{
if (entity is AttributeDefinition)
{
var attDef = (AttributeDefinition)entity;
if (attDef.Constant)
{
CreateTextFromAttrib(attDef, br.Layer, owner, tr);
}
entity.Dispose();
}
else
{
if (entity.Layer == "0") entity.Layer = br.Layer;
if (entity.ColorIndex == 0) entity.ColorIndex = 256;
owner.AppendEntity(entity);
tr.AddNewlyCreatedDBObject(entity, true);
}
}
br.Erase();
}
private static void CreateTextFromAttrib(DBText att, string layer, BlockTableRecord owner, Transaction tr)
{
var text = new DBText
{
Rotation = att.Rotation,
TextString = att.TextString,
Height = att.Height,
Justify = att.Justify,
Position = att.Position
};
text.SetPropertiesFrom(att);
if (att.Justify != AttachmentPoint.BaseLeft)
{
text.AlignmentPoint = att.AlignmentPoint;
}
if (text.Layer == "0") text.Layer = layer;
if (text.ColorIndex == 0) text.ColorIndex = 256;
owner.AppendEntity(text);
tr.AddNewlyCreatedDBObject(text, true);
}