如何通过 Lambda 表达式创建 AutoCAD 对象并返回

我是 C# 编程(和一般编程)的新手,但我正在使用 AutoDesk .NET API 进行工作项目的 AutoCAD 开发。


在 AutoCAD 开发中有一些重复的任务,我一直在创建帮助方法来简化我的代码。为了通过 .API 在 AutoCAD 中创建对象(线、多段线、注释等),程序员必须编写一个相当复杂的语句来访问 AutoCAD 环境,获取当前图形,获取数据库当前绘图文件,开始与数据库的事务//do work,然后在最终提交和关闭事务之前将创建的实体附加到数据库。


所以我写了下面的代码来简化这个任务:


public static void CreateObjectActionWithinTransaction(Action<Transaction, Database, BlockTable, BlockTableRecord> action)

{

    var document = Application.DocumentManager.MdiActiveDocument;

    var database = document.Database;

    using (var transaction = document.TransactionManager.StartTransaction())

    {

        BlockTable blocktable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;

        BlockTableRecord blockTableRecord = transaction.GetObject(blocktable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

        action(transaction, database, blocktable, blockTableRecord);


        transaction.Commit();

    }

}

然后我的 Lambda 表达式创建一个泛型MText并为其设置一些参数:


public static void createMtext(Point3d location, AttachmentPoint attachmentpoint, string contents, double height, short color, bool usebackgroundmask, bool usebackgroundcolor, double backgroundscale)

{

    CreateObjectActionWithinTransaction((transaction, database, blocktable, blocktablerecord) =>

    {

        MText mt = new MText();

    });

}

最后,当我实际在MText某处创建时,我可以在一行中创建它,并为所有参数传入值,而无需为其编写庞大的事务代码:


Helpers.createMtext(insertpoint, AttachmentPoint.MiddleLeft, "hello world", .08, colors.AutoCAD_Red, true, true, 1.2);

所以这很棒,当我想自己创建一个MText并将它放在某个地方时它可以工作。但是,在某些其他情况下MText,我想MText使用与上述相同的基本前提创建一个,而不是仅创建一个并将其放置在绘图中,但将其作为值返回以在其他地方使用。


AutoCAD 具有称为注释对象Multileaders,它们基本上MText就像上面一样,但附加到一些线和一个箭头以指向图形中的某些内容。在 API 中,您需要定义一个MText并将其附加到Multileader对象。但是我上面的代码不能使用,因为它没有返回任何东西。


所以我的问题归结为,我怎样才能创建一个像上面这样的方法来创建一个对象,而不是仅仅创建那个对象,让它返回那个对象以供另一段代码使用?


对于 Lambda 表达式的初学者,还有什么好的资源吗?书籍、网站、YouTube?


眼眸繁星
浏览 169回答 3
3回答

qq_笑_17

对于 AutoCAD 部分:正如 Miiir 在评论中所说,不要返回对象,而是ObjectId.&nbsp;一个对象实例属于一个事务,因此如果您使用某个事务打开该对象,提交该事务并尝试在另一个事务中使用该对象,AutoCAD 基本上只会崩溃。使用 AutoCAD API始终遵循以下基本模式:开始交易创建新对象或使用事务来获取现有对象。这可以通过使用ObjectID或 遍历表并查找您感兴趣的任何属性(即BlockTable、BlockTableRecord、LayerTable等)来完成。对对象做一些事情。提交或中止事务。如果您尝试绕过第 1 步和第 2 步,则效果不会很好。所以, return&nbsp;ObjectID,然后使用 id 在另一个事务中获取对象。至于 C# 部分:如果您希望使用委托返回值,那Action<T>不是您的朋友。Action不返回值,它只是“行动”,因此得名。如果您想使用委托返回一个值,您有 2 个选项:定义自定义委托类型。使用 .NET 框架提供的通用委托Func<T1,T2,T3,T4,TResult>。你应该使用哪一个?在您的情况下,我可能会选择选项 1,原因很简单,因为您的代码将更加简洁且易于维护。我将在这个例子中使用它。使用Func的工作方式完全相同,只是你的函数签名看起来有点难看。自定义委托://somewhere in your code inside a namespace (rather than a class)public delegate ObjectId MyCreateDelegate(Transaction transaction, Database db,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;BlockTable blockTable, BlockTableRecord blockTableRecord);然后你的一般方法public static ObjectId CreateObjectActionWithinTransaction(MyCreateDelegate createDel){&nbsp; &nbsp; ObjectId ret;&nbsp; &nbsp; var document = Application.DocumentManager.MdiActiveDocument;&nbsp; &nbsp; var database = document.Database;&nbsp; &nbsp; using (var transaction = document.TransactionManager.StartTransaction())&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; BlockTable blocktable = transaction.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;&nbsp; &nbsp; &nbsp; &nbsp; BlockTableRecord blockTableRecord = transaction.GetObject(blocktable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;&nbsp; &nbsp; &nbsp; &nbsp; //here createMtext will get called in this case, and return ObjectID&nbsp; &nbsp; &nbsp; &nbsp; ret = createDel(transaction, database, blocktable, blockTableRecord);&nbsp; &nbsp; &nbsp; &nbsp; transaction.Commit();&nbsp; &nbsp; }&nbsp; &nbsp; return ret;}以及使用 lambda 的具体方法:public ObjectId createMtext(Point3d location, AttachmentPoint attachmentpoint, string contents, double height, short color, bool usebackgroundmask, bool usebackgroundcolor, double backgroundscale){&nbsp; &nbsp; //here you can return the result the general function&nbsp; &nbsp; return CreateObjectActionWithinTransaction((transaction, database, blocktable, blocktablerecord) =>&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; MText mt = new MText();&nbsp; &nbsp; &nbsp; &nbsp; mt.SetDatabaseDefaults();&nbsp; &nbsp; &nbsp; &nbsp; mt.Location = location;&nbsp; &nbsp; &nbsp; &nbsp; mt.Attachment = attachmentpoint;&nbsp; &nbsp; &nbsp; &nbsp; mt.Contents = contents;&nbsp; &nbsp; &nbsp; &nbsp; mt.Height = height;&nbsp; &nbsp; &nbsp; &nbsp; mt.Color = Color.FromColorIndex(ColorMethod.ByAci, color);&nbsp; &nbsp; &nbsp; &nbsp; mt.BackgroundFill = usebackgroundmask;&nbsp; &nbsp; &nbsp; &nbsp; mt.UseBackgroundColor = usebackgroundcolor;&nbsp; &nbsp; &nbsp; &nbsp; mt.BackgroundScaleFactor = backgroundscale;&nbsp; &nbsp; &nbsp; &nbsp; blocktablerecord.AppendEntity(mt);&nbsp; &nbsp; &nbsp; &nbsp; transaction.AddNewlyCreatedDBObject(mt, true);&nbsp; &nbsp; &nbsp; &nbsp; //make sure to get ObjectId only AFTER adding to db.&nbsp; &nbsp; &nbsp; &nbsp; return mt.ObjectId;&nbsp; &nbsp; });}最后,像这样使用它ObjectId mtId = Helpers.createMtext(insertpoint, AttachmentPoint.MiddleLeft, "hello world", .08, colors.AutoCAD_Red, true, true, 1.2);//now use another transaction to open the object and do stuff to it.

斯蒂芬大帝

我宁愿使用从调用方法中的事务中调用的扩展方法,而不是使用委托。static class ExtensionMethods{&nbsp; &nbsp; public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var tr = db.TransactionManager.TopTransaction;&nbsp; &nbsp; &nbsp; &nbsp; if (tr == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);&nbsp; &nbsp; &nbsp; &nbsp; return (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), mode);&nbsp; &nbsp; }&nbsp; &nbsp; public static void Add(this BlockTableRecord btr, Entity entity)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var tr = btr.Database.TransactionManager.TopTransaction;&nbsp; &nbsp; &nbsp; &nbsp; if (tr == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NoActiveTransactions);&nbsp; &nbsp; &nbsp; &nbsp; btr.AppendEntity(entity);&nbsp; &nbsp; &nbsp; &nbsp; tr.AddNewlyCreatedDBObject(entity, true);&nbsp; &nbsp; }&nbsp; &nbsp; public static MText AddMtext(this BlockTableRecord btr,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; Point3d location,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; AttachmentPoint attachmentpoint,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; string contents,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; double height,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; short color = 256,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; bool usebackgroundmask = false,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; bool usebackgroundcolor = false,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; double backgroundscale = 1.5)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; MText mt = new MText();&nbsp; &nbsp; &nbsp; &nbsp; mt.SetDatabaseDefaults();&nbsp; &nbsp; &nbsp; &nbsp; mt.Location = location;&nbsp; &nbsp; &nbsp; &nbsp; mt.Attachment = attachmentpoint;&nbsp; &nbsp; &nbsp; &nbsp; mt.Contents = contents;&nbsp; &nbsp; &nbsp; &nbsp; mt.Height = height;&nbsp; &nbsp; &nbsp; &nbsp; mt.ColorIndex = color;&nbsp; &nbsp; &nbsp; &nbsp; mt.BackgroundFill = usebackgroundmask;&nbsp; &nbsp; &nbsp; &nbsp; mt.UseBackgroundColor = usebackgroundcolor;&nbsp; &nbsp; &nbsp; &nbsp; mt.BackgroundScaleFactor = backgroundscale;&nbsp; &nbsp; &nbsp; &nbsp; btr.Add(mt);&nbsp; &nbsp; &nbsp; &nbsp; return mt;&nbsp; &nbsp; }}使用示例:&nbsp; &nbsp; &nbsp; &nbsp; public static void Test()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var doc = AcAp.DocumentManager.MdiActiveDocument;&nbsp; &nbsp; &nbsp; &nbsp; var db = doc.Database;&nbsp; &nbsp; &nbsp; &nbsp; using (var tr = db.TransactionManager.StartTransaction())&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var ms = db.GetModelSpace(OpenMode.ForWrite);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var mt = ms.AddMtext(Point3d.Origin, AttachmentPoint.TopLeft, "foobar", 2.5);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // do what you want with 'mt'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr.Commit();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }

largeQ

我不熟悉 AutoCad API,但似乎“transaction.Commit()”是实际执行将 MText 放置在模型上的操作的行。如果是这种情况;我会做如下的事情:public MText CreateMTextObject({parameters}){//code&nbsp; Return textObject}public PlaceTextObject({parameters}){&nbsp; CreateTextObject(parameters).Commit()}这样,您可以选择保留文本对象以供进一步操作,同时仍然允许选择一次性应用它。它也将只有一个用于制作对象的代码块,确保两种方法的实现没有差异
打开App,查看更多内容
随时随地看视频慕课网APP