Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Kazikin от 21-04-2017, 14:05:53

Название: Изменение объекта запустившего событие Modified
Отправлено: Kazikin от 21-04-2017, 14:05:53
Добрый день!

Тут https://sites.google.com/site/bushmansnetlaboratory/translate-manual/ispolzovanie-sobytij/rekomendacii-otnositelno-obrabotcikov-sobytij (https://sites.google.com/site/bushmansnetlaboratory/translate-manual/ispolzovanie-sobytij/rekomendacii-otnositelno-obrabotcikov-sobytij) черным по белому написано:
Цитировать
Вы можете записать данные любого объекта в базу данных, но избегайте изменять объект, который вызвал событие.
    Очевидно, что любой объект вызвавший событие, может быть в настоящее время еще открыт и над ним может происходить какое либо действие. По этому избегайте изменений этого объекта из обработчика событий. Тем не менее вы смело можете считать информацию из объекта, который запустил событие.

Есть ли способы по обходу данного запрета?

Опишу задачу, которая встала передо мной. Есть вхождение динамического блока с атрибутом. При изменении параметра дин.блока хочу изменить значение атрибута. Но при Commit(), вываливается ошибка: AccessViolationException. Похоже, что происходит описанное в цитате. Как можно "дождаться" пока объект освободится?

Подскажите, как быть, пожалуйста.
Название: Re: Изменение объекта запустившего событие Modified
Отправлено: Александр Ривилис от 21-04-2017, 14:12:37
При изменении параметра дин.блока хочу изменить значение атрибута.
Не понятен контекст. Имеется в виду в событии изменения параметра динамического блока? Или ты сам меняешь параметр и сразу же хочешь изменить значение атрибута? Это разные вещи. Короче говоря лучше покажи код.
Название: Re: Изменение объекта запустившего событие Modified
Отправлено: Kazikin от 21-04-2017, 14:26:45
Хочу чтобы при изменении пользователем геометрических параметров Блока изменялись так же и его атрибуты. И наоборот при изменении значения атрибута - изменялась геометрия.

К вхождению блока цепляю так:
Код - C# [Выбрать]
  1.  br.Modified += new EventHandler(SmoBlockMod);

Код - C# [Выбрать]
  1.         void SmoBlockMod(object senderObj, EventArgs evtArgs)
  2.         {
  3.             Document acDoc = acad.DocumentManager.MdiActiveDocument;
  4.             Database acCurDb = acDoc.Database;
  5.             Editor ed = acDoc.Editor;
  6.  
  7.             if (acCurDb.TransactionManager.NumberOfActiveTransactions == 0)
  8.                 if (senderObj.GetType() == typeof(BlockReference))
  9.                 {
  10.                     BlockReference br = senderObj as BlockReference;
  11.                     using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
  12.                     {
  13.                         double h = 0;
  14.  
  15.                         foreach (DynamicBlockReferenceProperty j in
  16.                             br.DynamicBlockReferencePropertyCollection)
  17.                         {
  18.                             if (j.PropertyName == "Высота")
  19.                                 h = Convert.ToDouble(j.Value);
  20.                         }
  21.  
  22.                         foreach (ObjectId attRefID in br.AttributeCollection)
  23.                         {
  24.                             DBObject obj = acTrans.GetObject(attRefID,
  25.                                 OpenMode.ForRead);
  26.  
  27.                             AttributeReference attRef = obj as AttributeReference;
  28.  
  29.                             if (attRef != null)
  30.                                 if (attRef.Tag == "ВЫСОТА")
  31.                                 {
  32.                                     attRef.UpgradeOpen();
  33.                                     attRef.TextString = Convert.ToString(Math.Round(h / 1000, 1));
  34.                                     attRef.DowngradeOpen();
  35.                                 }
  36.                         }
  37.  
  38.                         acTrans.Commit();
  39.                     }
  40.                 }
  41.             ed.Regen();
  42.         }
Название: Re: Изменение объекта запустившего событие Modified
Отправлено: avc от 21-04-2017, 14:27:31
Я думаю, что модифицировать любые объекты по событию модификации - это уже плохая практика. Я предпочитаю просто запоминать ID измененного объекта и делать всю обработку в событии простоя или в doc_CommandEnded.
Конечно тут есть подводные камни: до вызова обработчика может быть модифицированно много объектов, может быть удален объект, может быть изменен несколько раз. И вообще может обработчик не вызваться и данные рассинхронизируются (в этом конкретном случае не будет соответствия параметра и атрибута). Значит доверять данным в атрибуте нельзя.
Название: Re: Изменение объекта запустившего событие Modified
Отправлено: avc от 21-04-2017, 14:39:30
... и что-то мне кажется вам просто надо в блоке сделать атрибут, отображающий отформатированное значение параметра. Разве это не делается штатными средствами бе з программирования? Я не спец по динамическим блокам, но я б покопал в эту сторону
Название: Re: Изменение объекта запустившего событие Modified
Отправлено: Александр Ривилис от 21-04-2017, 14:47:17
Kazikin
1. Однозначно Editor.Regen запускать в событии изменения объекта нельзя.
2. Можно попробовать заменить acCurDb.TransactionManager.StartTransaction() на acCurDb.TransactionManager.StartOpenCloseTransaction()
3. avc прав и так делать не следует вообще. Обработка должна осуществляться не в этом событии. В этом событии ты лишь запоминаешь ObjectId примитива, который потом будешь обрабатывать в другом событии.