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

ADN Club => AutoCAD .NET API => Тема начата: Даниил от 15-02-2015, 17:45:06

Название: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 17:45:06
Здравствуйте. Не так давно задавал вопрос по поводу обновления чертежа - нужно было выделять объект и подсвечивать его на чертеже. Получил решение используя Editor.UpdateScreen.

Однако выяснил, что данное решение не помогает мне при изменении параметров объекта. Имею следующую проблему:

1. Из диалогового окна WPF задаю новые параметры для объекта/слоя
2. При записи новых параметров, выполняю метод Refresh().

Код - C# [Выбрать]
  1. public static void Refresh(Document document)
  2.         {
  3.             document.Editor.UpdateScreen();
  4.         }

3. Но чертеж не обновляется сразу же после нажатия кнопки изменить "объект". Вижу изменения только при установке фокуса на окно чертежа.

Ниже привожу исходных код метода, обновляющего параметры объекта/слоя:

Код - C# [Выбрать]
  1. public static void ChangeObject(string id, int colorIndex, bool visible, string name, string objectClass,
  2.             double pointX1, double pointX2, double pointY1, double pointY2, double circleRadius, double pointZ)
  3.         {
  4.             doc = Application.DocumentManager.MdiActiveDocument;
  5.             db = doc.Database;
  6.             using (doc.LockDocument())
  7.  
  8.             {
  9.                 using (trans = db.TransactionManager.StartOpenCloseTransaction())
  10.                 {
  11.                     if (objectClass == "Слой")
  12.                     {
  13.                         var lt = trans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
  14.                         if (lt != null)
  15.                         {
  16.                             foreach (var objId in lt)
  17.                             {
  18.                                 var ltr = trans.GetObject(objId, OpenMode.ForWrite) as LayerTableRecord;
  19.                                 if (ltr.Id.ToString() == id)
  20.                                 {
  21.                                     ltr.Color = Color.FromColorIndex(ColorMethod.ByAci,
  22.                                             short.Parse(colorIndex.ToString()));
  23.                                     ltr.Name = name;
  24.                                     ltr.IsOff = visible != true;
  25.                                 }
  26.                             }
  27.                         }
  28.                         trans.Commit();
  29.                     }
  30.                     else
  31.                     {
  32.                         PromptSelectionResult getSel = doc.Editor.SelectAll();
  33.                        
  34.                         if (getSel.Status == PromptStatus.OK)
  35.                         {
  36.                             SelectionSet selSet = getSel.Value;
  37.  
  38.                             foreach (SelectedObject selObj in selSet)
  39.                             {
  40.                                 switch (objectClass)
  41.                                 {
  42.                                     case "Точка":
  43.                                         var point = trans.GetObject(selObj.ObjectId, OpenMode.ForWrite) as DBPoint;
  44.                                         if (point != null && point.Id.ToString() == id)
  45.                                         {
  46.                                             //Type entType = ent.GetType();
  47.                                             //switch (entType.Name)
  48.                                             point.Position = new Point3d(pointX1, pointY1, pointZ);
  49.                                             //line = new Line();
  50.                                             //circle = new Circle();
  51.                                         }
  52.                                         break;
  53.                                     case "Линия":
  54.                                         var line = trans.GetObject(selObj.ObjectId, OpenMode.ForWrite) as Line;
  55.                                         if (line != null && line.Id.ToString() == id)
  56.                                         {
  57.                                             line.StartPoint = new Point3d(pointX1, pointY1, pointZ);
  58.                                             line.EndPoint = new Point3d(pointX2, pointY2, pointZ);
  59.                                         }
  60.                                         break;
  61.                                     case "Окружность":
  62.                                         var circle = trans.GetObject(selObj.ObjectId, OpenMode.ForWrite) as Circle;
  63.                                         if (circle != null && circle.Id.ToString() == id)
  64.                                         {
  65.                                             circle.Center = new Point3d(pointX1, pointY1, pointZ);
  66.                                             circle.Radius = circleRadius;
  67.                                         }
  68.                                         break;
  69.                                     default:
  70.                                         MessageBox.Show("Выберите объект, для которого необходимо внести изменения");
  71.                                         return;
  72.                                 }
  73.                             }
  74.                         }
  75.                         trans.Commit();
  76.                     }
  77.                 }
  78.             }
  79.             Refresh(doc);
  80.         }


Код - C# [Выбрать]
  1. string id, int colorIndex, bool visible, string name, string objectClass,
  2.             double pointX1, double pointX2, double pointY1, double pointY2, double circleRadius, double pointZ

Это соответствующий набор значений параметров, которые должны быть установлены для выбранного в диалоговом окне объекта. Чувствую, что решение простое, но, возможно, слишком закопался и не вижу его на поверхности.  Буду благодарен Вам за помощь.

Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 18:02:18
Радикальный метод:
Код - C# [Выбрать]
  1. document.Editor.Regen();
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 18:10:37
В случае, когда меняю параметры линии/точки/окружности - помогло, однако если меняю параметры слоя, например цвет, обновления не происходит. В чем может быть проблема?
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 18:12:10
однако если меняю параметры слоя, например цвет, обновления не происходит.
А должно? Обновление чего должно произойти?
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 18:15:00
Я изменяю, к примеру, видимость слоя, свойство IsOff. Соответственно все объекты, относящиеся к слою должны стать невидимыми. И это происходит, но только при фокусировке на окне чертежа.
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 18:18:47
Ну попробуй ещё:
Код - C# [Выбрать]
  1. document.Editor.ApplyCurDwgLayerTableChanges();
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 18:22:19
Хм, такой метод не предусмотрен, судя по тому, что выдает студия. Видимо версия dll, что использую, не включает его, буду разбираться. Спасибо)
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 18:24:28
В какой версии AutoCAD?
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 18:24:52
AutoCAD 2012
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 18:31:11
В 2012 такого метода не было. Тогда нужно пользоваться P/Invoke для функции:
Код - C++ [Выбрать]
  1. void acdbApplyCurDwgLayerTableChanges();
Почитай эту тему: http://www.caduser.ru/forum/index.php?PAGE_NAME=message&FID=49&TID=48608&MID=271364#message271364
 
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 19:04:05
Где-то так:
Код - C# [Выбрать]
  1. [DllImport("acad.exe",
  2.            EntryPoint = "?acdbApplyCurDwgLayerTableChanges@@YAXXZ",
  3.            CallingConvention = CallingConvention.Cdecl)]
  4. private static extern void acdbApplyCurDwgLayerTableChanges();
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 19:17:52
Попробовал данный вариант, проблема осталась: только при фокусировке обновляется чертеж. Проблема актуальна только для слоев.
Своеобразным костылем прикрутил MessageBox, который говорит мне о том, что слой обновлен, и показывает его свойства, т.к. после нажатия ОК происходит фокусировка на чертеже и объекты пропадают.

Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 19:24:41
Попробовал данный вариант, проблема осталась: только при фокусировке обновляется чертеж.
Ну тогда для фокусировки ты можешь воспользоваться методом:
Код - C# [Выбрать]
  1. Autodesk.AutoCAD.Internal.Utils.SetFocusToDwgView();
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 19:41:07
Кстати, еще и замени строку
Код - C# [Выбрать]
  1. using (trans = db.TransactionManager.StartOpenCloseTransaction())
на
Код - C# [Выбрать]
  1. using (trans = doc.TransactionManager.StartOpenCloseTransaction())
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 19:48:04
Я внимательнее посмотрел на твой код и у меня остатки волос стали дыбом.
1) Зачем передавать id в виде строки? Почему не передать нормально ObjectId
2) Зачем передавать objectClass, если эта информация есть в ObjectId?
3) Зачем перебирать все слои чтобы найти слой с известным ObjectId?
4) Зачем перебирать все примитивы чертежа для того чтобы найти примитив с заданным ObjectId?
5) ...
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 20:13:16
Я с Вами согласен, ввиду того, что это мой первый опыт работы с AutoCad через .net, в основном использовал примеры, которые находил в интернете и документации, и должного внимания не уделил коду. Как раз собираюсь этим заняться.

с ClassObject понял

а по поводу string Id. Я получал ID от выбранного элемента и записывал его в стринговую переменную, через ToString, т.к., на сколько я понимаю, тип данные ObjectId - intPtr. Не разобрался, как с ним работать. И мне показалось логично хранить ID объекта в string.

Ну и передаю его соответственно в метод как String. Как я понимаю, приведение string типа к типу intPtr должно помочь уйти от перебора слоев и поиска нужного Id.

Надеюсь, что объяснил более менее понятно.


с перебором, действительно, загнался немного. Id известен, достаточно его передать и внести нужные изменения.

Фокусировка помогла в моей проблеме, спасибо Вам большое.
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Александр Ривилис от 15-02-2015, 20:23:57
Фокусировка помогла в моей проблеме, спасибо Вам большое.
Отлично.
а по поводу string Id. Я получал ID от выбранного элемента и записывал его в стринговую переменную, через ToString, т.к., на сколько я понимаю, тип данные ObjectId - intPtr. Не разобрался, как с ним работать. И мне показалось логично хранить ID объекта в string.
Совершенно нелогично хранить ID в string. Причин две:
1) ID - это постоянное значение, но только в пределах одного сеанса работы с AutoCAD. Т.е. при следующем открытии этого чертежа у этого объекта будет другой ID. Поэтому смысла хранить его в виде строки нет никакого. Для этой цели есть Handle, который в виде строки хранится в чертеже и он одинаков в разных сеансах работы с AutoCAD.
2) Во внутреннем представлении ID имеет тип long.
Название: Re: Обновление чертежа при изменении слоя или объекта
Отправлено: Даниил от 15-02-2015, 20:26:15
Согласен, действительно сделал лишнее. Можно без проблем хранить ObjectID, затем передавать его в метод для внесения нужных изменений. Не заметил сразу этого. Ну и скорость работы должна заметно увеличится.

Спасибо за замечания. Учту их на будущее.