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

ADN Club => AutoCAD .NET API => Тема начата: MikhailTAP от 26-02-2015, 14:17:25

Название: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 14:17:25
Добрый день!
Есть плагин, который использует мультилинии. Их стили содержатся в шаблонах(для создаваемых документов), и в файлах *.mln(для обновления уже существующих чертежей). От версии к версии необходимо обновить стили мультилиний в соответствии с актуальными файлами *.mln, в которых стили называются также но имеют другие настройки. При подгрузке через метод Database.LoadMlineStyleFile, или аналог через P/Invoke ничего не обновляется. Стили не меняют настройки. Пробовал сначала вырезать все мультилинии на чертеже, потом удалить все стили линий, и подгрузить их заново указанными выше методами, однако получаю eWasErased при создании мультилиний (указывая им свои стили, которые были подгружены). И стили в окне MLSTYLE не меняются.

Код - C# [Выбрать]
  1.                         using (doc.LockDocument())
  2.                         using (var trans = doc.Database.TransactionManager.StartTransaction())
  3.                         using (var styles = (DBDictionary)trans.GetObject(doc.Database.MLStyleDictionaryId, OpenMode.ForRead))
  4.                         {
  5.                                 var objects = new List<ObjectId>();
  6.                                 foreach (var style in styles)
  7.                                 {
  8.                                         using (var mlstyle = (MlineStyle)trans.GetObject(style.Value, OpenMode.ForWrite))
  9.                                         {
  10.                                                 //mlstyle.Name = mlstyle.Name + "___";
  11.                                                 objects.Add(style.Value);
  12.                                                 mlstyle.Erase(true);
  13.                                         }
  14.                                 }
  15.  
  16.                                 doc.Database.Purge(new ObjectIdCollection(objects.ToArray()));
  17.  
  18.                                 trans.Commit();
  19.                         }
  20.  

Есть ли вариант как-то обновить стили?

Спасибо.
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 14:23:18
Как вариант: можно программно сравнить исходный и целевой стили между собой (каждую опцию настроек) и в случае необходимости внести соответствующие корректировки в целевой. Поскольку свойств не так уж и много, то трудностей это представлять не должно. Пример программной настройки стиля мультилинии можно глянуть здесь (http://bushman-andrey.blogspot.ru/2014/06/autocad_3409.html).
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 14:25:08
Я тоже об этом подумал, однако проблема в том, что стили в файлах mln. А как из них получить объект стиля мультилинии?
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 14:33:23
проблема в том, что стили в файлах mln. А как из них получить объект стиля мультилинии?
это обычные текстовые файлы, так что читать\редактировать их не должно представлять каких-либо трудностей. :)
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 26-02-2015, 15:15:24
Думаю, что нужно:
1) Переименовать те стили в чертеже, которые ты хочешь обновить
2) Загрузить Database.LoadMlineStyleFile
3) Задать новые стили.
4) Старые стили удалить.
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 16:20:04
Думаю, что нужно:
1) Переименовать те стили в чертеже, которые ты хочешь обновить
2) Загрузить Database.LoadMlineStyleFile
3) Задать новые стили.
4) Старые стили удалить.

Проверить полностью весь порядок смогу только завтра, но могу сказать что пробовал переименовывать стили мультилиний в чертеже, и следом загружать стили из файлов mln, вызывая правда функцию через P/Invoke, однако переименовываются стили нормально, но не подгружаются, в окне MLSTYLE стили не появляются.
Однако, немного предыстории, почему я вообще стал звать функцию загрузки из либы. Я изначально пытался загружать "поверх" стили методом Database.LoadMlineStyleFile, однако если стиль уже присутствовал в чертеже, генерировалось исключение, а если удалить вручную стили мультилиний из чертежа, сохранить, а потом открыть снова(для надежности так сказать), то этот метод сыпал исключение xxxAccessFilexxx(точно не вспомню). Погуглив это исключение, я наткнулся на Ваш пост, Александр:) На нём вы посоветовали использовать функцию из либы.
Я воспользовался этим советом, и стал звать функцию из либы. И бьюсь об заклад, что при подгрузке "поверх" стилей, они обновлялись как надо. Но на следующий день метод перестал работать. Откуда такое поведение - непонятно.
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 26-02-2015, 16:22:31
На нём вы посоветовали использовать функцию из либы.
Переведи. Желательно с ссылкой на то, что я писал.
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 16:29:52
Александр, вот ссылка http://forums.autodesk.com/t5/net/error-loading-a-multiline-style/td-p/1678971 старый пост (аж 2006 год:)). Вообще насколько я понял, eFileAccessErr по заявлению саппорта Автодеска за 2013 г может появляться при использовании метода Database.LoadMlineStyleFile если файл стиля расположен не в системной директории. Хотя в моём случае, путь до директории где лежали стили, был прописан в настройках автокада.
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 16:31:30
Ну, во первых, нельзя удалять все стили. Должен присутствовать как минимум стиль standard, а ты пытаешься и его удалить.
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 26-02-2015, 16:35:14
Должен присутствовать как минимум стиль standard, а ты пытаешься и его удалить.
Нельзя удалять также и текущий стиль и все используемые в чертеже стили. Ты же их сначала удаляешь, а затем уже проверяешь можно ли их удалить. В чем смысл?
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 16:41:18
Да, согласен, изменять/удалять системные объекты - плохое дело, но тем не менее, я у себя на чертеже перед этим удалял все(!) мультилинии. Но тем не менее, не могу понять, почему повторная загрузка стилей(через инвок, без удаления) работала, а потмо перестала о_О.
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 26-02-2015, 16:46:22
Ну тут как минимум нужно смотреть на твой код. Как минимум MLStyleDictionary должна быть доступна для записи в момент когда ты выполняешь загрузку *.mln-файлов. И вообще желательно, чтобы это действие было вне транзакции.
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 16:53:57
Цитировать
я у себя на чертеже перед этим удалял все(!) мультилинии. Но тем не менее, не могу понять, почему повторная загрузка стилей(через инвок, без удаления) работала, а потмо перестала о_О.
Ну-ну... Пробовал после этого войти в редактор стилей мультилиний? :)

Не занимайся ерундой. Тебе сказали, что нельзя удалять стандартные и текущие стили. То, что у тебя там "что-то работало, а потом перестало" - весьма сомнительно. В любом случае это "что-то" покоцало базу данных твоего чертежа и рано или поздно это всё равно вылезло бы. Кстати, возможно, что в свой шаблон ты как раз коцанный чертёж и вогнал. Соответственно всё, созданное на его основе так же криво.

Вот подправленный твой код (собственно, от "твоего" там почти ничего и не осталось):
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. #if AUTOCAD
  6. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  7. using Ap = Autodesk.AutoCAD.ApplicationServices;
  8. using Db = Autodesk.AutoCAD.DatabaseServices;
  9. using Ed = Autodesk.AutoCAD.EditorInput;
  10. using Rt = Autodesk.AutoCAD.Runtime;
  11. using Gm = Autodesk.AutoCAD.Geometry;
  12. using Hs = Autodesk.AutoCAD.DatabaseServices.HostApplicationServices;
  13. using Us = Autodesk.AutoCAD.DatabaseServices.SymbolUtilityServices;
  14. #endif
  15.  
  16. namespace cad_sandbox {
  17.   public class Class1 {
  18.     [Rt.CommandMethod("test")]
  19.     public void Test() {
  20.       Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  21.       Ed.Editor ed = doc.Editor;
  22.       Db.Database db = doc.Database;
  23.  
  24.       using (doc.LockDocument()) {
  25.         using (var trans = doc.Database.TransactionManager.StartTransaction()) {
  26.           Db.DBDictionary styles = trans.GetObject(db.MLStyleDictionaryId,
  27.             Db.OpenMode.ForRead) as Db.DBDictionary;
  28.           List<Db.ObjectId> objects = new List<Db.ObjectId>();
  29.           foreach (var style in styles) {
  30.             if (db.CmlstyleID != style.Value &&
  31.               style.Key.ToLower() != "standard") {
  32.               objects.Add(style.Value);
  33.             }
  34.           }
  35.  
  36.           if (objects.Count > 0) {
  37.             doc.Database.Purge(new Db.ObjectIdCollection(objects.ToArray()));
  38.           }
  39.  
  40.           foreach (var item in objects) {
  41.             var mlstyle = (Db.MlineStyle)trans.GetObject(item,
  42.               Db.OpenMode.ForWrite);
  43.             mlstyle.Erase(true);
  44.           }
  45.           trans.Commit();
  46.         }
  47.       }
  48.     }
  49.   }
  50. }
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 16:57:52
Спасибо за помощь, завтра попробую.
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 17:30:06
юзингов-то в своём коде ты понатыкал... я поубирал лишние.
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 17:34:13
Цитировать
я у себя на чертеже перед этим удалял все(!) мультилинии. Но тем не менее, не могу понять, почему повторная загрузка стилей(через инвок, без удаления) работала, а потмо перестала о_О.
Ну-ну... Пробовал после этого войти в редактор стилей мультилиний? :)

Не занимайся ерундой. Тебе сказали, что нельзя удалять стандартные и текущие стили. То, что у тебя там "что-то работало, а потом перестало" - весьма сомнительно. В любом случае это "что-то" покоцало базу данных твоего чертежа и рано или поздно это всё равно вылезло бы. Кстати, возможно, что в свой шаблон ты как раз коцанный чертёж и вогнал. Соответственно всё, созданное на его основе так же криво.

Вот подправленный твой код (собственно, от "твоего" там почти ничего и не осталось):
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. #if AUTOCAD
  6. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  7. using Ap = Autodesk.AutoCAD.ApplicationServices;
  8. using Db = Autodesk.AutoCAD.DatabaseServices;
  9. using Ed = Autodesk.AutoCAD.EditorInput;
  10. using Rt = Autodesk.AutoCAD.Runtime;
  11. using Gm = Autodesk.AutoCAD.Geometry;
  12. using Hs = Autodesk.AutoCAD.DatabaseServices.HostApplicationServices;
  13. using Us = Autodesk.AutoCAD.DatabaseServices.SymbolUtilityServices;
  14. #endif
  15.  
  16. namespace cad_sandbox {
  17.   public class Class1 {
  18.     [Rt.CommandMethod("test")]
  19.     public void Test() {
  20.       Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  21.       Ed.Editor ed = doc.Editor;
  22.       Db.Database db = doc.Database;
  23.  
  24.       using (doc.LockDocument()) {
  25.         using (var trans = doc.Database.TransactionManager.StartTransaction()) {
  26.           Db.DBDictionary styles = trans.GetObject(db.MLStyleDictionaryId,
  27.             Db.OpenMode.ForRead) as Db.DBDictionary;
  28.           List<Db.ObjectId> objects = new List<Db.ObjectId>();
  29.           foreach (var style in styles) {
  30.             if (db.CmlstyleID != style.Value &&
  31.               style.Key.ToLower() != "standard") {
  32.               objects.Add(style.Value);
  33.             }
  34.           }
  35.  
  36.           doc.Database.Purge(new Db.ObjectIdCollection(objects.ToArray()));
  37.  
  38.           foreach (var item in objects) {
  39.             var mlstyle = (Db.MlineStyle)trans.GetObject(item,
  40.               Db.OpenMode.ForWrite);
  41.             mlstyle.Erase(true);
  42.           }
  43.           trans.Commit();
  44.         }
  45.       }
  46.     }
  47.   }
  48. }
Андрей, Вы наверное не так поняли меня. Во-первых, ни шаблон, ни чертёж не сохранялся, поэтому ничего "коцанного" нет.
Во-вторых, на  счёт "сомнительно". Я пробовал БЕЗ УДАЛЕНИЯ(!) старых стилей подгружать ПОВЕРХ(!) стили из файлов. Именно в таком(!) виде оно работало. Не сочтите за офтоп конечно, но я задавая вопросы здесь, стараюсь вникнуть в суть проблемы, каждый раз подчерпывая для себя информацию о том, как устроен внутри Автокад. Поэтому и указал этот странный момент в своём сообщении, стараясь указать как можно больше информации, чтобы получить конкретный ответ.
За помощь спасибо:)
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 26-02-2015, 17:35:52
юзингов-то в своём коде ты понатыкал... я поубирал лишние.
Разве получая объект по транзакции неправильно диспоузить его?
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 26-02-2015, 17:39:39
Разве получая объект по транзакции неправильно диспоузить его?
Транзакция сделает это за тебя. Подробнее можешь почитать здесь (http://bushman-andrey.blogspot.ru/2013/01/database-autocad.html), либо здесь (http://www.private.peterlink.ru/poleshchuk/cad/2014/Pr2013-2015.htm). К сожалению, в книге (по моей вине) по этой теме присутствует досадная опечатка\ошибка (о поведениях по умолчанию). В обозначенной по первой ссылке записи блога она исправлена.
Название: Re: Обновить стили мультилиний
Отправлено: MikhailTAP от 27-02-2015, 07:01:10
Андрей, пробовал с Вашим вариантом удаления, но потерпел неудачу. Вот код

Код - C# [Выбрать]
  1. public static void AppendAllMultilineType(Document doc, string scale, string appDir)
  2.                 {
  3.                         using (doc.LockDocument())
  4.                         using (var trans = doc.Database.TransactionManager.StartTransaction())
  5.                         using (var styles = (DBDictionary)trans.GetObject(doc.Database.MLStyleDictionaryId, OpenMode.ForWrite))
  6.                         {
  7.                                 var objects = new List<ObjectId>();
  8.                                 foreach (var style in styles)
  9.                                 {
  10.                                         if (style.Key.Equals("STANDARD", StringComparison.CurrentCultureIgnoreCase) || style.Value == doc.Database.CmlstyleID)
  11.                                                 continue;
  12.  
  13.                                         objects.Add(style.Value);
  14.                                 }
  15.  
  16.                                 if (objects.Any())
  17.                                         doc.Database.Purge(new ObjectIdCollection(objects.ToArray()));
  18.  
  19.                                 foreach (var style in objects)
  20.                                 {
  21.                                         var mlstyle = (MlineStyle)trans.GetObject(style, OpenMode.ForWrite);
  22.                                         mlstyle.Erase(true);
  23.                                 }
  24.  
  25.                                 trans.Commit();
  26.                         }
  27.  
  28.                         using (doc.Database.MLStyleDictionaryId.GetObject(OpenMode.ForWrite))
  29.                         {
  30.                                 var files = Directory.GetFiles(appDir, String.Format("*{0}.mln", scale));
  31.  
  32.                                 foreach (var file in files)
  33.                                 {
  34.                                         var styleName = file.Substring(file.LastIndexOf('\\') + 1);
  35.                                         styleName = styleName.Remove(styleName.IndexOf('_'));
  36.                                         try
  37.                                         {
  38.                                                 doc.Database.LoadMlineStyleFile(styleName, file);
  39.                                         }
  40.                                         catch
  41.                                         {
  42.                                         }
  43.                                 }
  44.                         }
  45.                 }
  46.  

Опять при назначении стиля мультилинии возникает исключение ошибка eWasErased. Подгрузку пробовал переносить и над trans.Commit() - результат тот же.

При попытке переименовать, а потом следом подгрузить стили из файлов тоже безуспешны. Переименовываются норм, а вот подгрузка происходит "мимо", стили не появляются. Более того, если следом попытаться назначить стиль для мультилинии со старым названием, то никаких исключения не генерируется. А в словаре далее в плагине мы находим без проблем все стили по старым именам(как до изменения). Это при том, что в окне MLSTYLE имена меняются, а в словаре нет.

Код - C# [Выбрать]
  1.                 public static void AppendAllMultilineType(Document doc, string scale, string appDir)
  2.                 {
  3.                         using (doc.LockDocument())
  4.                         using (var trans = doc.Database.TransactionManager.StartTransaction())
  5.                         using (var styles = (DBDictionary)trans.GetObject(doc.Database.MLStyleDictionaryId, OpenMode.ForWrite))
  6.                         {
  7.                                 foreach (var style in styles)
  8.                                 {
  9.                                         if (style.Key.Equals("STANDARD", StringComparison.CurrentCultureIgnoreCase) || style.Value == doc.Database.CmlstyleID)
  10.                                                 continue;
  11.                                         var mlstyle = (MlineStyle)trans.GetObject(style.Value, OpenMode.ForWrite);
  12.                                         mlstyle.Name += "_";
  13.  
  14.                                 }
  15.  
  16.                                 trans.Commit();
  17.                         }
  18.  
  19.                         using (doc.Database.MLStyleDictionaryId.GetObject(OpenMode.ForWrite))
  20.                         {
  21.                                 var files = Directory.GetFiles(appDir, String.Format("*{0}.mln", scale));
  22.  
  23.                                 foreach (var file in files)
  24.                                 {
  25.                                         var styleName = file.Substring(file.LastIndexOf('\\') + 1);
  26.                                         styleName = styleName.Remove(styleName.IndexOf('_'));
  27.                                         try
  28.                                         {
  29.                                                 doc.Database.LoadMlineStyleFile(styleName, file);
  30.                                         }
  31.                                         catch
  32.                                         {
  33.                                         }
  34.                                 }
  35.                         }
  36.                 }
  37.  
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 27-02-2015, 10:08:08
Цитировать
пробовал с Вашим вариантом удаления, но потерпел неудачу. Вот код
То, что ты показываешь - это однозначно не мой код.

Выложи DWG файл, на котором запускал код.
Название: Re: Обновить стили мультилиний
Отправлено: Андрей Бушман от 27-02-2015, 10:44:16
Цитировать
пробовал с Вашим вариантом удаления, но потерпел неудачу
Согласен, нужно добавить проверку на наличие элементов в списке objects, прежде чем вызывать Purge, иначе получаем ошибку, если удалять нечего. Добавил выше эту проверку в коде (http://adn-cis.org/forum/index.php?topic=1900.msg7550#msg7550) (см. строку 36).
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 27-02-2015, 22:02:39
MikhailTAP
1) Мне начинает надоедать форматировать твой код. Прочитай мою подпись и в дальнейшем придерживайся правил форматирования на форуме.
2) Если нужна помощь - выкладывай чертеж, mln-файлы и тестовый проект, который у тебя не работает.
Название: Re: Обновить стили мультилиний
Отправлено: Александр Ривилис от 27-02-2015, 22:05:31
Для переименования насколько я помню следует использовать метод DBDictionary.SetName(string oldName, string newName);