Andrew Truckle
Andrew Truckle

Reputation: 19157

Adding elements to model space the correct way using .NET API

Method One

_AcDb.Line oLine = new _AcDb.Line(ptStart, ptEnd);
AddToModelSpace("PLOT", oLine);

Where AddToModelSpace is:

public static void AddToModelSpace(string strLayer, _AcDb.Entity oEntity)
{
    _AcAp.Document acDoc = _AcAp.Application.DocumentManager.MdiActiveDocument;
    _AcDb.Database acCurDb = acDoc.Database;
    _AcEd.Editor ed = acDoc.Editor;

    using (_AcDb.BlockTable bt = acCurDb.BlockTableId.GetObject(_AcDb.OpenMode.ForRead) as _AcDb.BlockTable)
    using (_AcDb.BlockTableRecord ms = bt[_AcDb.BlockTableRecord.ModelSpace].GetObject(_AcDb.OpenMode.ForWrite) as _AcDb.BlockTableRecord)
        ms.AppendEntity(oEntity);
    oEntity.Layer = strLayer;
    oEntity.Dispose();
}

Method Two

// Get the current document and database
_AcAp.Document docActive = _AcAp.Application.DocumentManager.MdiActiveDocument;
_AcDb.Database docDB = docActive.Database;

// Start a transaction
using (_AcDb.Transaction acTrans = docDB.TransactionManager.StartTransaction())
{
    // Open the Block table for read
    _AcDb.BlockTable acBlkTbl;
    acBlkTbl = acTrans.GetObject(docDB.BlockTableId,
                                    _AcDb.OpenMode.ForRead) as _AcDb.BlockTable;

    // Open the Block table record Model space for write
    _AcDb.BlockTableRecord acBlkTblRec;
    acBlkTblRec = acTrans.GetObject(acBlkTbl[_AcDb.BlockTableRecord.ModelSpace],
                                    _AcDb.OpenMode.ForWrite) as _AcDb.BlockTableRecord;

    // Create line
    using (_AcDb.Line acLine = new _AcDb.Line(ptStart, ptEnd))
    {

        // Add the new object to the block table record and the transaction
        acBlkTblRec.AppendEntity(acLine);
        acTrans.AddNewlyCreatedDBObject(acLine, true);
    }

    // Save the new object to the database
    acTrans.Commit();
}

I have used AddToModelSpace in my project so I hope it is fine!

Upvotes: 0

Views: 1327

Answers (1)

gileCAD
gileCAD

Reputation: 2493

Method Two is the way Autodesk recommends in the developer's documentation (you can read this section).

In Method One, you use the ObjectId.GetObject() method to open the BlockTable and the model space 'BlockTableRecord'. This method uses the top transaction to open object which means that there's an active transaction you should use to add the newly created entity. You can get it with Database.TransactionManager.TopTransaction. If you don't want to use a transaction at all, you have to use the "for advanced use only" ObjectId.Open() method.

A Method Three should be using some extension methods to be called from within a transaction. Here's a simplified (non error checking) extract of the ones I use.

static class ExtensionMethods
{
    public static T GetObject<T>(
        this ObjectId id, 
        OpenMode mode = OpenMode.ForRead,
        bool openErased = false, 
        bool forceOpenOnLockedLayer = false)
        where T : DBObject
    {
        return (T)id.GetObject(mode, openErased, forceOpenOnLockedLayer);
    }

    public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead)
    {
        return SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject<BlockTableRecord>(mode);
    }

    public static ObjectId Add (this BlockTableRecord owner, Entity entity)
    {
        var tr = owner.Database.TransactionManager.TopTransaction;
        var id = owner.AppendEntity(entity);
        tr.AddNewlyCreatedDBObject(entity, true);
        return id;
    }
}

Using example:

using (var tr = db.TransactionManager.StartTransaction())
{
    var line = new Line(startPt, endPt) { Layer = layerName };
    db.GetModelSpace(OpenMode.ForWrite).Add(line);
    tr.Commit();
}

Upvotes: 2

Related Questions