Всем привет. Вопрос в продолжение моих многочисленных тем по поводу динамического редактирования графики внутри анонимного блока. Мы уже много чего обсуждали и частично
подобную тему тоже.
У меня работает все практически как надо, но вот столкнулся с неприятным моментом при обработке команды UNDO.
Все действия происходят в ObjectOverrule:
public override void Close(DBObject dbObject)
{
if (IsApplicable(dbObject))
{
if (!OverrulesInteraction.IsGripOverruleWork)
{
if (dbObject != null &&
dbObject.IsModified &
!dbObject.IsErased &
!dbObject.IsEraseStatusToggled &
!dbObject.IsModifiedXData &
!dbObject.IsNewObject &
!dbObject.IsCancelling
)
{
var breakLine = BreakLineXDataHelper.GetBreakLineFromEntity((Autodesk.AutoCAD.DatabaseServices.Entity)dbObject);
if (breakLine != null)
{
breakLine.UpdateEntities();
breakLine.BlockRecord.UpdateAnonymousBlocks();
using (ResultBuffer resBuf = breakLine.GetParametersForXData())
{
dbObject.XData = resBuf;
}
}
}
else if (dbObject != null && dbObject.IsUndoing & dbObject.IsModifiedXData)
{
var breakLine = BreakLineXDataHelper.GetBreakLineFromEntity((Autodesk.AutoCAD.DatabaseServices.Entity)dbObject);
if (breakLine != null)
{
breakLine.UpdateEntities();
breakLine.BlockRecord.UpdateAnonymousBlocks();
}
}
}
}
base.Close(dbObject);
}
Я специально вынес в отдельное условие
else if (dbObject != null && dbObject.IsUndoing & dbObject.IsModifiedXData) чтобы было удобней работать.
Сначала я получаю экземпляр класса, описывающий графику внутри блока методом GetBreakLineFromEntity():
public static BreakLine GetBreakLineFromEntity(Autodesk.AutoCAD.DatabaseServices.Entity ent)
{
using (ResultBuffer resBuf = ent.GetXDataForApplication(BreakLineFunction.MPCOEntName))
{
BreakLine breakLine = new BreakLine(ent.ObjectId);
// Получаем параметры из самого блока
// ОБЯЗАТЕЛЬНО СНАЧАЛА ИЗ БЛОКА!!!!!!
breakLine.GetParametersFromEntity(ent);
// Получаем параметры из XData
breakLine.GetParametersFromResBuf(resBuf);
return breakLine;
}
}
В этом методе в первую очередь я получаю данные из самого блока, а потом уже из расширенных данных блока.
Затем вызываю метод UpdateEntities(), который эту графику (примитивы внутри блока) перерисовывает по новым данным (точкам) и затем получаю BlockTableRecord:
private BlockTableRecord _blockRecord;
public BlockTableRecord BlockRecord
{
get
{
try
{
if (!BlockId.IsNull)
{
using (AcadHelpers.Document.LockDocument())
{
using (var tr = AcadHelpers.Database.TransactionManager.StartTransaction())
{
var blkRef = (BlockReference)tr.GetObject(BlockId, OpenMode.ForWrite);
_blockRecord = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
if (_blockRecord.GetBlockReferenceIds(true, true).Count <= 1)
{
foreach (var objectId in _blockRecord)
{
tr.GetObject(objectId, OpenMode.ForWrite).Erase();
}
}
else
{
_blockRecord = new BlockTableRecord { Name = "*U" , BlockScaling = BlockScaling.Uniform };
using (var blockTable = AcadHelpers.Database.BlockTableId.Write<BlockTable>())
{
if (Annotative)
{
_blockRecord.Annotative = AnnotativeStates.True;
}
blockTable.Add(_blockRecord);
tr.AddNewlyCreatedDBObject(_blockRecord, true);
}
blkRef.BlockTableRecord = _blockRecord.Id;
}
tr.Commit();
}
using (var tr = AcadHelpers.Database.TransactionManager.StartTransaction())
{
var blkRef = (BlockReference)tr.GetObject(BlockId, OpenMode.ForWrite);
_blockRecord = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
_blockRecord.BlockScaling = BlockScaling.Uniform;
var matrix3D = Matrix3d.Displacement(-InsertionPoint.TransformBy(BlockTransform.Inverse()).GetAsVector());
foreach (var entity in Entities)
{
var transformedCopy = entity.GetTransformedCopy(matrix3D);
_blockRecord.AppendEntity(transformedCopy);
AcadHelpers.Document.TransactionManager.AddNewlyCreatedDBObject(transformedCopy, true);
}
tr.Commit();
}
try
{
AcadHelpers.Document.TransactionManager.FlushGraphics();
}
catch (Exception exception)
{
MpExWin.Show(exception);
}
}
}
else if (!IsValueCreated)
{
var matrix3D = Matrix3d.Displacement(-InsertionPoint.TransformBy(BlockTransform.Inverse()).GetAsVector());
foreach (var ent in Entities)
{
var transformedCopy = ent.GetTransformedCopy(matrix3D);
_blockRecord.AppendEntity(transformedCopy);
}
IsValueCreated = true;
}
}
catch (Exception exception)
{
MpExWin.Show(exception);
}
return _blockRecord;
}
set => _blockRecord = value;
}
Для которого вызываю метод UpdateAnonymousBlocks().
Как мы видим, при получении BlockTableRecord сначала удаляются все примитивы, а затем добавляются новые. Я перепроверил – после команды UNDO все данные – я имею ввиду XData – корректно обновляются в примитиве так как нужно и до того, как происходит метод ObjectOverrule.Close(). Т.е. все данные, нужные чтобы вернуть графику в нужный вид, есть.
И вот самое интересное – после вызова команды UNDO у меня графика внутри блока дублируется! Т.е. остается та, которая была перед вызовом команды UNDO и та, которая должна стать как надо. Причем если вызвать какие-то события, которые снова приведут к «обновлению» блока, то вся графика станет верной – т.е. ненужная копия исчезнет.
Использование регенерации, TransactionManager.FlushGraphics() и ((BlockReference)dbObject).RecordGraphicsModified(true) не дает эффекта.