ObjectOverrule.Close: Обновить BlockTableRecord для BlockReference

Автор Тема: ObjectOverrule.Close: Обновить BlockTableRecord для BlockReference  (Прочитано 9936 раз)

0 Пользователей и 5 Гостей просматривают эту тему.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Все - сдаюсь! Уже очень много испробовал вариантов - и логичных и нелогичных. Не могу никак понять правильный порядок действий (чувствую, что вот где-то рядом)
Имеется анонимный блок. Мне нужно изменять содержимое BlockTableRecord для вхождения блока. Т.е. получается всегда один BlockTableRecord и для него один BlockReference.
Для "описания" содержимого блока используется специальный класс, в котором я запоминаю ObjectId вхождения блока.
Для обновления содержимого получаются такие действия:
1. Я получаю экземпляр моего описательного класса по выбранному блоку
2. Я вызываю метод, которые обновляет геометрию (для примера - полилинию)
3. Затем методом из того-же класса я обновляю и BlockTableRecord:
     3.1. По сохраненному ObjectId получаю BlockReference. По нему получаю BlockTableRecord в котором все стирается
     3.2. В BlockTableRecord добавляется новое содержимое
4. Я вызываю метод UpdateAnonymousBlocks() для BlockTableRecord что вызывает и обновление BlockReference.
Так вот вся загвоздка в том, что для пункта 3 нужно открывать транзакцию!
При использовании этих шагов в GripsOverrule все отлично работает и никаких проблем нет. Но мне нужно, чтобы блок обновлялся и при изменении его свойств. А тут остается только ObjectOverrule.Close(). Но при всех возможных вариантах что-то сделать в ObjectOverrule.Close() (который срабатывает для BlockReference) ловятся фатальные ошибки. Причем, на попытках открыть транзакцию в п.3. Что в общем-то логично, т.к. BlockReference у меня в этот момент уже открыт и я его пытаюсь открыть опять
В общем - я уже порядком запутался =(
Как мне кажется - для обновления из GripsOverrule мне нужно оставить п.3, а при обновлении из ObjectOverrule.Close() мне нужно как-то использовать п.3 без транзакций
Поправьте и подскажите, если я что не так понимаю. А то и поговорить-то не с кем об этом ))

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Причем самое интересное то, что у меня частично получается реализовать описанное. Изменение блока ручками работает. Изменение блока через палитру свойств или некоторые команды (масштабирование) работает. Но когда я беру два таких блока, перемещаю ручки в одну точку и потом меняю их за ручку (т.е. два блока одновременно), то ловится фатал. И ловится он именно в ObjectOverrule.Close(). Но почему - вообще ума не приложу

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Так вот вся загвоздка в том, что для пункта 3 нужно открывать транзакцию!
Не нужно. Ты не умеешь работать без транзакции? http://adn-cis.org/sozdanie-polyline3d-bez-ispolzovaniya-tranzakczii.html
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Так вот вся загвоздка в том, что для пункта 3 нужно открывать транзакцию!
Не нужно. Ты не умеешь работать без транзакции? http://adn-cis.org/sozdanie-polyline3d-bez-ispolzovaniya-tranzakczii.html
Вот только не работает
Из тела метода ObjectOverrule.Close() пытаюсь получить BlockTableRecord для текущего BlockReference и сразу ловлю ошибку "Ссылка на объект не указывает на экземпляр объекта." на строчке:
Код - C# [Выбрать]
  1. var blockRecord = (BlockTableRecord)blkRef.BlockTableRecord.GetObject(OpenMode.ForWrite);

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Из тела метода ObjectOverrule.Close() пытаюсь получить BlockTableRecord для текущего BlockReference и сразу ловлю ошибку "Ссылка на объект не указывает на экземпляр объекта." на строчке:
Разницу между ObjectId.GetObject и ObjectId.Open чувствуешь? Статью прочитал внимательно?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Из тела метода ObjectOverrule.Close() пытаюсь получить BlockTableRecord для текущего BlockReference и сразу ловлю ошибку "Ссылка на объект не указывает на экземпляр объекта." на строчке:
Разницу между ObjectId.GetObject и ObjectId.Open чувствуешь? Статью прочитал внимательно?
Оп-ля - невнимательно! К вечеру внимание рассеялось  ::)
Завтра буду пробовать

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Не, вариант с Open никак не прокатывает. Как и вариант ObjectId.GetObject.
Вот что у меня имеется:
Код - C# [Выбрать]
  1. private BlockTableRecord _blockRecord;
  2. public BlockTableRecord BlockRecord
  3. {
  4.     get
  5.     {
  6.         try
  7.         {
  8.             if (!BlockId.IsNull)
  9.             {
  10.                 using (var tr = AcadHelpers.Database.TransactionManager.StartTransaction())
  11.                 {
  12.                     var blkRef = (BlockReference)tr.GetObject(BlockId, OpenMode.ForWrite);
  13.                     _blockRecord = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
  14.                     _blockRecord.BlockScaling = BlockScaling.Uniform;
  15.                     if (_blockRecord.GetBlockReferenceIds(true, true).Count <= 1)
  16.                     {
  17.                         foreach (var objectId in _blockRecord)
  18.                         {
  19.                             objectId.GetObject(OpenMode.ForWrite).Erase(true);
  20.                         }
  21.                     }
  22.                     else
  23.                     {
  24.                         var blockTable = (BlockTable)tr.GetObject(AcadHelpers.Database.BlockTableId, OpenMode.ForWrite);
  25.                         _blockRecord = new BlockTableRecord { Name = "*U" };
  26.                         if (Annotative) _blockRecord.Annotative = AnnotativeStates.True;
  27.                         blockTable.Add(_blockRecord);
  28.                         tr.AddNewlyCreatedDBObject(_blockRecord, true);
  29.                         blkRef.BlockTableRecord = _blockRecord.Id;
  30.                     }
  31.                     tr.Commit();
  32.                 }
  33.                 using (var tr = AcadHelpers.Database.TransactionManager.StartTransaction())
  34.                 {
  35.                     var blkRef = (BlockReference)tr.GetObject(BlockId, OpenMode.ForWrite);
  36.                     _blockRecord = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
  37.                     var matrix3D = Matrix3d.Displacement(-InsertionPoint.GetAsVector()) * GetCurrentMatrixForBlockUpdate();
  38.                     foreach (var entity in Entities)
  39.                     {
  40.                         var transformedCopy = entity.GetTransformedCopy(matrix3D);
  41.                         _blockRecord.AppendEntity(transformedCopy);
  42.                         tr.AddNewlyCreatedDBObject(transformedCopy, true);
  43.                     }
  44.                     tr.Commit();
  45.                 }
  46.             }
  47.             else
  48.             {
  49.                 var matrix3D = Matrix3d.Displacement(-InsertionPoint.GetAsVector()) * GetCurrentMatrixForBlockUpdate();
  50.                 foreach (var ent in Entities)
  51.                 {
  52.                     var transformedCopy = ent.GetTransformedCopy(matrix3D);
  53.                     _blockRecord.AppendEntity(transformedCopy);
  54.                 }
  55.             }
  56.             return _blockRecord;
  57.         }
  58.  
  59.         catch (Exception exception)
  60.         {
  61.             MpExWin.Show(exception);
  62.             return null;
  63.         }
  64.     }
  65.     set => _blockRecord = value;
  66. }

Вариант с транзакцией в общем-то работает за исключением некоторых моментов. И самый гадкий из них, то, что метод ObjectOverrule.Close срабатывает и при копировании в буфер обмена, что вызывает новые ошибки

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
то, что метод ObjectOverrule.Close срабатывает и при копировании в буфер обмена, что вызывает новые ошибки
Есть ли способы в ObjectOverrule определить, что происходит копирование в буфер? Или только обработка событий начала и окончания функции помогут?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Есть ли способы в ObjectOverrule определить, что происходит копирование в буфер? Или только обработка событий начала и окончания функции помогут?
В AutoCAD .NET API специального события для этого нет. Можно попробовать использовать Win32 API для этого. Пример здесь: https://stackoverflow.com/questions/2226920/how-do-i-monitor-clipboard-content-changes-in-c
Но проще я думаю отслеживать события начала и окончания команд.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Решил свою проблему неожиданным для меня способом! )) Сейчас тестирую, но на первый взгляд работает. Конечно, после большего количества тестов что-нибудь выплывет, но буду решать проблемы по мере поступления.
В общем - в работе метода ObjectOverrule.Close() у меня есть проверка:
Код - C# [Выбрать]
  1. if (dbObject != null &&
  2.     dbObject.IsModified &
  3.     !dbObject.IsUndoing &
  4.     !dbObject.IsErased &
  5.     !dbObject.IsEraseStatusToggled &
  6.     !dbObject.IsModifiedXData
  7. )
И если все подходит - тогда происходит "перерисовка" блока
Так вот я в эту проверку добавил !dbObject.IsNewObject. Теперь при изменении блока копированием, перемещением, из палитры свойств и т.п. блок перерисовывается. И не возникает проблем с копированием блока в буфер обмена

UPD: Сейчас, перечитывая сообщение, подумал, что логично будет убрать !dbObject.IsUndoing

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
UPD: Сейчас, перечитывая сообщение, подумал, что логично будет убрать !dbObject.IsUndoing
Тогда, возможно, стоит убрать и !dbObject.IsEraseStatusToggled