GripOverrule. Фатальная ошибка, если ручки двух объектов совпадают

Автор Тема: GripOverrule. Фатальная ошибка, если ручки двух объектов совпадают  (Прочитано 8424 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Сделал переопределение ручек. Все нормально работает до того момента, пока я не перемещу одинаковые ручки двух объектов в одну точку. После этого ловится фатальная ошибка - либо просто при выборе этих объектов, либо при попытке перетащить эти ручки. С горем пополам при отладке я смог уловить одну ошибку (не ловится через try{}catch{}) - System.ArgumentException: Элемент с тем же ключом уже был добавлен
У меня создан свой GripData в котором есть ссылка на ObjectId объекта. Так же создал энумератор с "именами" ручек вместо использования индекса:
Код - C# [Выбрать]
  1. public enum BreakLineGripName
  2. {
  3.     StartGrip,
  4.     MiddleGrip,
  5.     EndGrip
  6. }
GripData выглядит примерно так (убрал toolTip'ы):
Код - C# [Выбрать]
  1. public class BreakLineGrip : MPCOGrips.MPCOGripData
  2. {
  3.     // Ссылка на ObjectId блока
  4.     public ObjectId BlkRef { get; set; }
  5.     // Экземпляр класса, связанный с этим блоком
  6.     public BreakLine breakLine { get; set; }
  7.     // Имя ручки
  8.     public BreakLineGripName GripName { get; set; }
  9.  
  10.     // Временное значение первой ручки
  11.     private Point3d _startGripTmp;
  12.     // временное значение последней ручки
  13.     private Point3d _endGripTmp;
  14.  
  15.     public override void OnGripStatusChanged(ObjectId entityId, Status newStatus)
  16.     {
  17.         try
  18.         {
  19.             // Запоминаем начальные значения
  20.             if (newStatus == Status.GripStart)
  21.             {
  22.                 if (GripName == BreakLineGripName.StartGrip)
  23.                     _startGripTmp = GripPoint;
  24.                 if (GripName == BreakLineGripName.EndGrip)
  25.                     _endGripTmp = GripPoint;
  26.                 if (GripName == BreakLineGripName.MiddleGrip)
  27.                 {
  28.                     _startGripTmp = breakLine.StartGrip;
  29.                     _endGripTmp = breakLine.EndGrip;
  30.                 }
  31.             }
  32.             // Сохраняем данные в расширенные данные примитива
  33.             if (newStatus == Status.GripEnd)
  34.             {
  35.                 using (var tr = AcadHelpers.Database.TransactionManager.StartTransaction())
  36.                 {
  37.                     var blkRef = tr.GetObject(breakLine.BlockId, OpenMode.ForWrite);
  38.                     using (var resBuf = breakLine.GetParametersForXData())
  39.                     {
  40.                         blkRef.XData = resBuf;
  41.                     }
  42.                     tr.Commit();
  43.                 }
  44.             }
  45.             // При отмене перемещения возвращаем временные значения
  46.             if (newStatus == Status.GripAbort)
  47.             {
  48.                 if (_startGripTmp != null & GripName == BreakLineGripName.StartGrip)
  49.                     breakLine.EndPoint = GripPoint;
  50.                 if (GripName == BreakLineGripName.MiddleGrip & _startGripTmp != null & _endGripTmp != null)
  51.                 {
  52.                     breakLine.InsertionPoint = _startGripTmp;
  53.                     breakLine.EndPoint = _endGripTmp;
  54.                 }
  55.             }
  56.             base.OnGripStatusChanged(entityId, newStatus);
  57.         }
  58.         catch (Exception exception)
  59.         {
  60.             MpExWin.Show(exception);
  61.         }
  62.     }
  63. }
При работе метода GetGripPoints я получаю ручки и добавляю их в коллекцию
Код - C# [Выбрать]
  1. if (IsApplicable(entity))
  2. {
  3.     // Удаляем стандартную ручку позиции блока (точки вставки)
  4.     GripData toRemove = null;
  5.     foreach (GripData gd in grips)
  6.     {
  7.         if (gd.GripPoint == blkRef.Position)
  8.         {
  9.             toRemove = gd;
  10.             break;
  11.         }
  12.     }
  13.     if (toRemove != null) grips.Remove(toRemove);
  14.     // Получаем ручки СПДС объекта
  15.     var breakLine = BreakLineXDataHelper.GetBreakLineFromEntity(entity);
  16.    
  17.     if (breakLine != null)
  18.     {
  19.         // add start grip
  20.         var gp = new BreakLineGrip
  21.         {
  22.             BlkRef = entity.ObjectId,
  23.             breakLine = breakLine,
  24.             GripName = BreakLineGripName.StartGrip,
  25.             GripPoint = breakLine.StartGrip
  26.         };
  27.         grips.Add(gp);
  28.         // add middle grip
  29.         gp = new BreakLineGrip
  30.         {
  31.             BlkRef = entity.ObjectId,
  32.             breakLine = breakLine,
  33.             GripName = BreakLineGripName.MiddleGrip,
  34.             GripPoint = breakLine.MiddleGrip
  35.         };
  36.         grips.Add(gp);
  37.         // add end grip
  38.         gp = new BreakLineGrip
  39.         {
  40.             BlkRef = entity.ObjectId,
  41.             breakLine = breakLine,
  42.             GripName = BreakLineGripName.EndGrip,
  43.             GripPoint = breakLine.EndGrip
  44.         };
  45.         grips.Add(gp);
  46.     }
  47. }
В методе MoveGripPointsAt я обновляю уже связанный с ручкой объект:
Код - C# [Выбрать]
  1. public override void MoveGripPointsAt(Autodesk.AutoCAD.DatabaseServices.Entity entity, GripDataCollection grips, Vector3d offset, MoveGripPointsFlags bitFlags)
  2. {
  3.     try
  4.     {
  5.         foreach (GripData gripData in grips)
  6.         {
  7.             var gripPoint = gripData as BreakLineGrip;
  8.  
  9.             if (gripPoint != null)
  10.             {
  11.                 if (gripPoint.GripName == BreakLineGripName.StartGrip)
  12.                 {
  13.                     ((BlockReference)entity).Position = gripPoint.GripPoint + offset;
  14.                     gripPoint.breakLine.InsertionPoint = gripPoint.GripPoint + offset;
  15.                 }
  16.                 if (gripPoint.GripName == BreakLineGripName.MiddleGrip)
  17.                 {
  18.                     var lenghtVector = (gripPoint.breakLine.InsertionPoint - gripPoint.breakLine.EndPoint) / 2;
  19.                     ((BlockReference)entity).Position = gripPoint.GripPoint + offset + lenghtVector;
  20.  
  21.                     gripPoint.breakLine.InsertionPoint = gripPoint.GripPoint + offset + lenghtVector;
  22.                     gripPoint.breakLine.EndPoint = gripPoint.GripPoint + offset - lenghtVector;
  23.                 }
  24.                 if (gripPoint.GripName == BreakLineGripName.EndGrip)
  25.                 {
  26.                     gripPoint.breakLine.EndPoint = gripPoint.GripPoint + offset;
  27.                 }
  28.  
  29.                 gripPoint.breakLine.UpdateEntities();
  30.                 gripPoint.breakLine.BlockRecord.UpdateAnonymousBlocks();
  31.             }
  32.             else base.MoveGripPointsAt(entity, grips, offset, bitFlags);
  33.         }
  34.     }
  35.     catch (Exception exception)
  36.     {
  37.         MpExWin.Show(exception);
  38.     }
  39. }

Разве при этом в коллекции GripDataCollection grips мои ручки не получаются уникальными? Описанный вариант работает кроме только одного случая - как у же говорил - если две ручки двух объектов не переместить в одну точку

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ничего не понял, кроме того, что у тебя где-то в коде ошибки. Причем наверняка как обычно не в той части кода, которую ты показал.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Ничего не понял
А вот так?
Извините, вам запрещён просмотр содержимого спойлеров.

Я отметил там место, где тоже может возникать ошибка. Но это в методе MoveGripPointsAt. А у меня фатал ловится еще задолго до работы этого метода - в методе GetGripPoints. Я смог один раз ее при отладке поймать и вот как она выглядела:
Цитировать
System.ArgumentException: Элемент с тем же ключом уже был добавлен.
   в System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   в System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   в AcMgGripOverrule.getGripPoints(AcMgGripOverrule* , AcDbEntity* pSubject, AcArray<AcDbGripData \*\,AcArrayMemCopyReallocator<AcDbGripData \*> >* grips, Double curViewUnitSize, Int32 gripSize, AcGeVector3d* curViewDir, Int32 bitflags)

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Дальше еще интересней. При работе метода MoveGripPointsAt создается копия примитива с ObjectId.Null (0). И по логике в моем коде часть с перерисовкой примитивов в блоке вообще не должна работать, но она работает почти всегда)) Если изменять один блок

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Извини, но разбираться в твоём коде у меня ни времени ни желания нет.
Сделай отдельный простейший тестовый проект (ничего лишнего) и если в нём при совпадении ручек будет проявляться ошибка - отправлю в ADN DevHelp.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
отправлю в ADN DevHelp
Можете отправить в ADN DevHelp вопрос - почему вот тут написано:
Цитировать
AcDbEntity* pSubject  - A pointer to an AcDbEntity that this overrule applies to.
А по факту передается ObjectId.Null

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
отправлю в ADN DevHelp
Можете отправить в ADN DevHelp вопрос - почему вот тут написано:
Цитировать
AcDbEntity* pSubject  - A pointer to an AcDbEntity that this overrule applies to.
А по факту передается ObjectId.Null
1. Ты путаешь ObjectARX и AutoCAD .NET API.
2. Передаётся Entity у которого ObjectId.Null. В чем тут противоречие? В случае если CloneMeForDragging возвращает true (а это по-умолчанию так и происходит) создаётся клон примитива и перетаскивание выполняется с ним. У клона (т.к. он не добавлен в Database) свойство ObjectId == ObjectId.Null
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Сделай отдельный простейший тестовый проект (ничего лишнего)
Сделал на сколько смог простейший проект. Приложил к ответу.
Вот видео примера с ошибкой:

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
До того, как я буду тестировать, уточни проверял ли ты в последних AutoCAD'ах (2016, 2017, 2018)? 2010-го у меня нет, так что проверить не смогу, да и отсылать в ADN DevHelp не буду - поддерживаются только последние три версии.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
До того, как я буду тестировать, уточни проверял ли ты в последних AutoCAD'ах (2016, 2017, 2018)? 2010-го у меня нет, так что проверить не смогу, да и отсылать в ADN DevHelp не буду - поддерживаются только последние три версии.
Нет. Только на 2010 автокаде. Завтра постараюсь проверить на 2017

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Нет. Только на 2010 автокаде. Завтра постараюсь проверить на 2017
Можешь не проверять. Я проверил в 2016 - всё работает нормально. Так что можно списать на баг в AutoCAD 2010:


Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Можешь не проверять. Я проверил в 2016 - всё работает нормально. Так что можно списать на баг в AutoCAD 2010:
Не только 2010. Я проверил на 2013 и 2017. На 2013 тоже фаталит. На 2017 все нормально. Получается, чтобы нормально использовать Overrules (в том варианте, что у меня в коде) нужно писать под 2016 и выше. Жаль

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Получается, чтобы нормально использовать Overrules (в том варианте, что у меня в коде) нужно писать под 2016 и выше. Жаль
Проверил на 2014 версии - нет фатала.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Проверил на 2014 версии - нет фатала.
Спасибо. Значит минимальной версией будет 2014

Отмечено как Решение Александр Ривилис 29-05-2017, 18:30:23

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
В методе SimplyGrip.OnGripStatusChanged убрал транзакцию: