newer 发表于 2021-1-8 23:47:00

.NET - System.NullReferenceException if draw method is called after layer is ...

.NET - System.NullReferenceException if draw method is called after layer is created

问题:

I need to add a layer and then add an entity to a drawing that will be on the new layer that is also created. After the entity is appended to modelspace and added to the transaction, but before the transaction is commited I need to call the entities' draw method. When I do this a System.NullReferenceException error occurs. Is there a work around for this problem?

解答:
The work around is to change a property of the layer after it has been added to the layer table. For example if the IsFrozen property of the new layer is changed then the error is resolved. The example below creates a new line and a new layer. Adding a new layer to the layer table should invalidate the layer cache. The problem is that the layer cache is not getting updated because the layer table is not "dirtied". (logged change request)

Note: The same problem will occur using the unmanaged C++ APIs. Also this problem may appear with this error:

"An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll"


using System;
using Autodesk.AutoCAD.DatabaseServices;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Windows.Forms;


namespace ClassLibrary2
{
public class Class1
{

public static void testLine()
{

   Database pDb = AcadApp.DocumentManager.MdiActiveDocument.Database;

   using (Transaction tr = pDb.TransactionManager.StartTransaction())
   {
    AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.EnableGraphicsFlush(true);

    using (Line line = new Line(new Point3d(0, 0, 0), new Point3d(100, 100, 0)))
    {
   try
   {
      ObjectId objId = getLayer("TestLayerName");
      line.LayerId = objId;

      BlockTable blkTable = (BlockTable)tr.GetObject(pDb.BlockTableId, OpenMode.ForRead);
      BlockTableRecord btrMSpace = (BlockTableRecord)tr.GetObject(blkTable, OpenMode.ForWrite);

      btrMSpace.AppendEntity(line);
      tr.AddNewlyCreatedDBObject(line, true);

      AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.FlushGraphics();
      line.Draw();
   }
   catch(System.Exception ex)
   {
      MessageBox.Show(ex.ToString());
   }
    }
    tr.Commit();
   }
}


private static ObjectId getLayer(string LayerName)
{
   Database DB = AcadApp.DocumentManager.MdiActiveDocument.Database;
   ObjectId tRetVal;
   using (Transaction tr = DB.TransactionManager.StartTransaction())
   {
    LayerTable tLtb = (LayerTable)tr.GetObject(DB.LayerTableId, OpenMode.ForWrite);
    if (tLtb.Has(LayerName))
    {
   tRetVal = tLtb;
    }
    else
    {
   using (LayerTableRecord tLtbRec = new LayerTableRecord())
   {
      tLtbRec.Name = LayerName;
      tLtbRec.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, Convert.ToInt16(6));

      tRetVal = tLtb.Add(tLtbRec);
      tr.AddNewlyCreatedDBObject(tLtbRec, true);
      //WORKAROUND: this will mark the layer table dirty so that FlushGraphics() will updated the layer cache
      //and thus line.Draw above works. It doesn't matter what value we are setting to IsFrozen: simply touching
      //the property will do the trick.
      tLtbRec.IsFrozen = false;
   }
    }
    tr.Commit();
   }

   return tRetVal;
}
}
}


页: [1]
查看完整版本: .NET - System.NullReferenceException if draw method is called after layer is ...