The Hatch.AppedLoop(HatchLoopTypes, ObjectIdCollection) method requires that the loop entities have valid ObjectId. That means that the entities that can be used as hatch's loops must belong to a BlockTableRecord and Database-residing.
So, the problem in your code is that even the polyline has been appended to the new BlockTableRecord, but before the new BlockTableRecord is added to BlockTable, the new BlockTableRecord is not database-residing, thus, its ObjectId is null, in turn the entities in the BlockTableRecord (the polyline) also has a null ObjectId. That is why the call to Hatch.AppendLoop() raises eInvalidInput exception.
Because Hatch's creation depends on database-residing entities as its loop, you cannot create it as your code shows before the new BlockTableRecord is added into BlockTable. So, you need to create the BlockTableRecord without hatch first, and then open the BlockTableRecord to modify it to add Hatch.
In this case, I'd rather do this similarly to what we do manually in AutoCAD: create (or select) existing entities in drawing (say, in ModelSpace), and use them to create a new BlockTableRecord, and then erase the existing entities (as an optional step). Here is the code that successfully creates a block definition with a hatched square:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
[assembly: CommandClass(typeof(CreateHatchedBlock.MyCadCommands))]
namespace CreateHatchedBlock
{
public class MyCadCommands
{
[CommandMethod("HatchedBlock")]
public static void CreateHatchedBlock()
{
Document dwg = CadApp.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;
//Create entities and get a available block name
ObjectId plId = ObjectId.Null;
ObjectId htId = ObjectId.Null;
string blkName = null;
using (var tran = dwg.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tran.GetObject(
dwg.Database.BlockTableId, OpenMode.ForRead);
blkName = GetNewBlockName(bt);
BlockTableRecord model = (BlockTableRecord)tran.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(dwg.Database),
OpenMode.ForWrite);
Polyline pl = CreateClosedPolyline();
plId = model.AppendEntity(pl);
tran.AddNewlyCreatedDBObject(pl, true);
Hatch hatch = CreateHatch(
new ObjectIdCollection(
new ObjectId[] { plId }));
htId = model.AppendEntity(hatch);
tran.AddNewlyCreatedDBObject(hatch, true);
tran.Commit();
}
//Create BlockTableRecord based on the 2 entities
ObjectId[] ids = new ObjectId[] { plId, htId };
CreateBlockDefinitionBasedOnExistingEntities(
dwg.Database, blkName, ids, true);
}
private static Polyline CreateClosedPolyline()
{
Polyline pl = new Polyline(4);
pl.AddVertexAt(0, new Point2d(0.0, 0.0), 0.0, 0.0, 0.0);
pl.AddVertexAt(1, new Point2d(4.0, 0.0), 0.0, 0.0, 0.0);
pl.AddVertexAt(2, new Point2d(4.0, 4.0), 0.0, 0.0, 0.0);
pl.AddVertexAt(3, new Point2d(0.0, 4.0), 0.0, 0.0, 0.0);
pl.Closed = true;
return pl;
}
private static Hatch CreateHatch(ObjectIdCollection loopIds)
{
Hatch ha = new Hatch();
ha.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
ha.Normal = Vector3d.ZAxis;
ha.AppendLoop(HatchLoopTypes.Default, loopIds);
ha.EvaluateHatch(true);
return ha;
}
private static string GetNewBlockName(BlockTable bt)
{
int i = 0;
string name = "TestBlock" + i;
while(bt.Has(name))
{
i++;
name = "TestBlock" + i;
}
return name;
}
private static void CreateBlockDefinitionBasedOnExistingEntities(
Database db, string blkName,
ObjectId[] ids, bool eraseEntities = false)
{
using (var tran = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tran.GetObject(
db.BlockTableId, OpenMode.ForWrite);
BlockTableRecord br = new BlockTableRecord();
br.Name = blkName;
br.Origin = new Point3d(0.0, 0.0, 0.0);
foreach (var id in ids)
{
Entity ent = (Entity)tran.GetObject(id, OpenMode.ForRead);
br.AppendEntity(ent.Clone() as Entity);
if (eraseEntities)
{
ent.UpgradeOpen();
ent.Erase(true);
}
}
bt.Add(br);
tran.AddNewlyCreatedDBObject(br, true);
tran.Commit();
}
}
}
}