Activist_Investor написано:
It's difficult to recommend if keeping your app data synchronized with that data its attached to is feasible, or the best solution, without knowing more about the specifics of your app, rather than the relatively-simple examples you are giving (the break line). For example you are not revealing what you are using the stored data for (a DrawableOverrule, perhaps?). I generally find it difficult to make recommendations about how to go about solving a problem without knowing all the details.
Ok, i'm trying to explain what i'm trying to do.
1. I create class thats discribe my base entity
2. I create class thats discribe my entity Inherited from base entity
This class contains points:
private Point3d _insertionPoint = Point3d.Origin;
/// <summary>
/// Точка вставки СПДС примитива. Должна быть у всех СПДС примитивов
/// </summary>
public Point3d InsertionPoint { get { return _insertionPoint; } set { _insertionPoint = value; UpdateEntities(); } }
private Point3d _middlePoint = Point3d.Origin;
/// <summary>
/// Средняя точка. Нужна для перемещения СПДС примитива
/// </summary>
public Point3d MiddlePoint { get { return _middlePoint; } set { _middlePoint = value; } }
private Point3d _endPoint = Point3d.Origin;
/// <summary>
/// Вторая (конечная) точка СПДС примитива
/// </summary>
public Point3d EndPoint { get { return _endPoint; } set { _endPoint = value; UpdateEntities(); } }
Sub entities:
private readonly Lazy<Polyline> _mainPolyline = new Lazy<Polyline>(() => new Polyline());
public Polyline MainPolyline => _mainPolyline.Value;
public override IEnumerable<Autodesk.AutoCAD.DatabaseServices.Entity> Entities
{
get
{
yield return MainPolyline;
//yield return other entities
}
}
And conatains void to update sub entities (or create its):
public void UpdateEntities()
{
var length = EndPoint.DistanceTo(InsertionPoint);
var scale = GetScale();
if (EndPoint.Equals(Point3d.Origin))
{
// Задание точки вставки (т.е. второй точки еще нет)
MakeSimplyEntity("SetInsertionPoint");
}
else if (length / scale < BreakLineMinLength)
{
// Задание второй точки - случай когда расстояние между точками меньше минимального
MakeSimplyEntity("SetEndPointMinLenght");
}
else
{
// Задание второй точки
Plane plane = new Plane();
var pts = PointsToCreatePolyline(scale, plane, InsertionPoint, EndPoint);
for (var i = 0; i < pts.Count; i++)
MainPolyline.SetPointAt(i, pts[i]);
}
}
3. I create Jig with Update method:
protected override bool Update()
{
try
{
using (AcadHelpers.Document.LockDocument(DocumentLockMode.ProtectedAutoWrite, null, null, true))
{
using (var tr = AcadHelpers.Document.TransactionManager.StartTransaction())
{
var obj = (BlockReference)tr.GetObject(Entity.Id, OpenMode.ForWrite, true);
obj.Erase(false);
obj.Position = BreakLine.InsertionPoint;
obj.BlockUnit = AcadHelpers.Database.Insunits;
tr.Commit();
}
BreakLine.UpdateEntities();
BreakLine.BlockRecord.UpdateAnonymousBlocks();
}
return true;
}
catch
{
// ignored
}
return false;
}
4. On starting function creating my entity, based on anonimus block:
[CommandMethod("ModPlus", "mpBreakLine", CommandFlags.Redraw)]
public void CreateBreakLine()
{
try
{
/* Регистрация СПДС приложения должна запускаться при запуске
* функции, т.к. регистрация происходит в текущем документе
* При инициализации плагина регистрации нет!
*/
ModPlus.SPDSHelpers.ExtendedDataHelpers.AddRegAppTableRecord();
//
var objectIdCollection = new ObjectIdCollection();
var contextCollection =
AcadHelpers.Database.ObjectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES");
var breakLine = new Entity.BreakLine(BreakLineFunction.currentStyle);
var blockReference = CreateBreakLineBlock(ref breakLine, contextCollection);
bool breakLoop = false;
while (!breakLoop)
{
var breakLineJig = new Jig.BreakLineJig(breakLine, blockReference);
do
{
label0:
var status = AcadHelpers.Editor.Drag(breakLineJig).Status;
if (status == PromptStatus.OK)
{
if (breakLineJig.JigState != BreakLineJigState.PromptInsertPoint)
{
breakLoop = true;
status = PromptStatus.Other;
}
else
{
breakLineJig.JigState = BreakLineJigState.PromptEndPoint;
goto label0;
}
}
else if (status != PromptStatus.Other)
{
using (AcadHelpers.Document.LockDocument())
{
using (var tr = AcadHelpers.Document.TransactionManager.StartTransaction())
{
var obj = (BlockReference)tr.GetObject(blockReference.Id, OpenMode.ForWrite);
obj.Erase(true);
tr.Commit();
}
}
breakLoop = true;
}
else
{
breakLine.UpdateEntities();
//var blockId = breakLine.BlockId;
breakLine.BlockRecord.UpdateAnonymousBlocks();
objectIdCollection.Add(breakLine.BlockId);
}
} while (!breakLoop);
}
}
catch (Autodesk.AutoCAD.Runtime.Exception exception)
{
MpExWin.Show(exception);
}
}
private static BlockReference CreateBreakLineBlock(ref Entity.BreakLine breakLine, ObjectContextCollection occ)
{
ObjectId objectId;
BlockReference blockReference;
using (AcadHelpers.Document.LockDocument())
{
using (var transaction = AcadHelpers.Document.TransactionManager.StartTransaction())
{
using (var blockTable = AcadHelpers.Database.BlockTableId.Write<BlockTable>())
{
var objectId1 = blockTable.Add(breakLine.BlockRecord);
blockReference = new BlockReference(breakLine.InsertionPoint, objectId1);
using (var blockTableRecord = AcadHelpers.Database.CurrentSpaceId.Write<BlockTableRecord>())
{
objectId = blockTableRecord.AppendEntity(blockReference);
// Добавление "метки" СПДС примитива
ModPlus.SPDSHelpers.ExtendedDataHelpers.SetSPDSentityNameToXData(BreakLineFunction.SPDSEntName, blockReference);
}
transaction.AddNewlyCreatedDBObject(blockReference, true);
transaction.AddNewlyCreatedDBObject(breakLine.BlockRecord, true);
}
transaction.Commit();
}
breakLine.BlockId = objectId;
//breakLine.UpdateParameters(objectId);
}
return blockReference;
}
The result is what I showed on the video.
As I see the problem - the class that describes my entity, put in the xrecord block. If change the block, change the xrecord. On GripsOvverlue, i can do this. But when editing the block by autocad's functions, I do not know how to do it.
This has already been implemented, but there are no source codes and I can not contact the author