Сохранение введенных параметров команды для повторного использования

Автор Тема: Сохранение введенных параметров команды для повторного использования  (Прочитано 8388 раз)

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

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

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Добрый день!
Прошу извинить за возможно глупый вопрос! Каким образом можно сохранять значения, введенные пользователем для использования при последующих вызовах моей команды. К примеру, моя команда при выборе соответствующей опции запрашивает величину угла или расстояния. Как введенную величину сохранить до следующего вызова, что бы использовать ее по умолчанию? И что бы это значение сохранялось в чертеже, где команда использовалась?
Шаблон для Visual Studio сообщает о такой возможности, но не вполне понятно, как ее использовать:
    ' This class is instantiated by AutoCAD for each document when
    ' a command is called by the user the first time in the context
    ' of a given document. In other words, non static data in this class
    ' is implicitly per-document!

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Шаблон сообщает совсем не об этом. Я лично предпочитаю хранить настройки своих плагинов в реестре независимо от чертежей. Сейчас делаю плагин работающий с блоками - сохраняю в атрибуты блока. Если надо сохранить в чертеж - я бы использовал словари и xRecord

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Хм... я использую обычную сериализацию и десериализацию в xml файл, который лежит в нужном месте.
Просто, быстро и очень, очень гибко.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Зависит от конкретной задачи
1. Если это одно значение в небольшом плагине без окна, то можно использовать хранение в XData чертежа. Правда в этом случае значение будет хранится в конкретном чертеже и в каждом новом будет использоваться значение по-умолчанию
2. Если вам не очень важно контролировать файл хранения параметров вашего плагина, то вам отлично подойдут возможности, которые предоставляет VisualStudio - свойства проекта, вкладка "Параметры". Достаточно гибкий инструмент, который все делает сам - и создает классы для работы с параметрами и папку хранения параметров, в которой хранится тот-же самый xml-файл. Папка создается в каталоге AppData пользователя. Главный плюс - стабильная работа
3. Ну и вариант, когда вы создаете свои методы хранения данных в нужном вам файле. Лучший и удобный, на мой взгляд, вариант - xml-файл. Есть конечно еще староверы, которые пользуются txt или ini =) Единственный минус - может случится такое, что файл испортится при записи в него данных. Это вы должны сами уже предусмотреть

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
2. Если вам не очень важно контролировать файл хранения параметров вашего плагина, то вам отлично подойдут возможности, которые предоставляет VisualStudio - свойства проекта, вкладка "Параметры". Достаточно гибкий инструмент, который все делает сам - и создает классы для работы с параметрами и папку хранения параметров, в которой хранится тот-же самый xml-файл. Папка создается в каталоге AppData пользователя. Главный плюс - стабильная работа
Я использую Visual Studio крайне эпизодически, ткните носом пожалуйста, как извлекать/записывать значения из своей процедуры в эти параметры?
Да и кстати, а как сам AutoCAD поступает с сохранением параметров своих команд? К примеру, команда ФАСКА. Параметры сохраняются в чертеже, в новом - параметры по умолчанию (а может из шаблона?)

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

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

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Если они сохраняются, то обычно в системных переменных
А можно ли такие системные переменные создавать? Если да, то каким образом?

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

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

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
2. Если вам не очень важно контролировать файл хранения параметров вашего плагина, то вам отлично подойдут возможности, которые предоставляет VisualStudio - свойства проекта, вкладка "Параметры". Достаточно гибкий инструмент, который все делает сам - и создает классы для работы с параметрами и папку хранения параметров, в которой хранится тот-же самый xml-файл. Папка создается в каталоге AppData пользователя. Главный плюс - стабильная работа
Александр, а можно поподробнее? Не очень понимаю, о чём речь.

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Александр, а можно поподробнее? Не очень понимаю, о чём речь.
В Visual Basic все оказалось достаточно просто: нужно открыть вкладку My Project в обозревателе решений, далее в ней открыть закладку Параметры. Там надо создать необходимые параметры. В коде их можно использовать через объект My.Settings. Соответствующие свойства объекта создаются автоматически, их можно читать/записывать. Эффективно, но не вижу возможности использовать значения по умолчанию для каждого нового чертежа. Свойства доcтупны для чтения и изменения из всех чертежей.
« Последнее редактирование: 12-03-2018, 10:39:58 от Phil »

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Раз вам все-таки надо хранить разные настройки в разных чертежах, то вариант с хранением во внешних файлах вам не подходит. Используйте пользовательские свойства чертежа или xData или xRecord для хранения любых своих данных внутри файла dwg

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Раз вам все-таки надо хранить разные настройки в разных чертежах, то вариант с хранением во внешних файлах вам не подходит. Используйте пользовательские свойства чертежа или xData или xRecord для хранения любых своих данных внутри файла dwg
xData и xRecord создаются для конкретных объектов? Как использовать пользовательские свойства чертежа?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Вот мой хелпер для записи в свойства чертежа
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Запись в свойства чертежа нового свойства или изменение старого
  3.     /// сохраняет все имеющиеся свойства чертежа
  4.     /// Document должен быть заблокирован
  5.     /// </summary>
  6.     /// <param name="ProrertyName">имя свойства. недопустимы двоеточия</param>
  7.     /// <param name="Value">значение свойства. будет преобразовано в строку</param>
  8.     /// <param name="doc">какому чертежу назначать. если null - текущему</param>
  9.     /// <returns>успех</returns>
  10.     public static bool SetDrawingProperty(this Database db, string ProrertyName, object Value)
  11.     {
  12.       if (db == null || string.IsNullOrEmpty(ProrertyName) || Value == null) return false;
  13.       DatabaseSummaryInfoBuilder ib = GetSummary(db);
  14.       IDictionaryEnumerator ff = db.SummaryInfo.CustomProperties;
  15.       while (ff.MoveNext())
  16.       {
  17.         if (ff.Key.ToString() != ProrertyName)
  18.           ib.CustomPropertyTable.Add(ff.Key, ff.Value);
  19.       }
  20.       ib.CustomPropertyTable.Add(ProrertyName, Value.ToString());
  21.       db.SummaryInfo = ib.ToDatabaseSummaryInfo();
  22.       return true;
  23.     }

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр, а можно поподробнее? Не очень понимаю, о чём речь.
Эффективно, но не вижу возможности использовать значения по умолчанию для каждого нового чертежа. Свойства доcтупны для чтения и изменения из всех чертежей.
Ну как я и сказал - открываете свойства проекта и идете на вкладку "Параметры". Её многие привыкли использовать для локализации (не лучший способ, ИМХО). Там ручками создаем параметры. При этом мы задаем тип данных и значение по умолчанию (которое Phil почему-то не увидел).



При этом VisualStudio создает специальный класс



Дальше уже в коде использовать эти параметры проще простого
Код - C# [Выбрать]
  1. var isCurrent = Properties.Settings.Default.IsCurrent;
При задании новых значений нужно не забывать вызывать метод сохранения, так как само это не происходит
Код - C# [Выбрать]
  1. Properties.Settings.Default.IsCurrent = true;
  2. Properties.Settings.Default.Save();

Еще эти параметры удобно биндить на WPF окна, что сокращает количество кода в разы

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Ну как я и сказал - открываете свойства проекта и идете на вкладку "Параметры". Её многие привыкли использовать для локализации (не лучший способ, ИМХО). Там ручками создаем параметры. При этом мы задаем тип данных и значение по умолчанию (которое Phil почему-то не увидел).
Значения по умолчанию я увидел и уже использовал. Проблема в другом: изменения этих параметров видят все открытые в данный момент чертежи. То есть они являются не локальными для каждого чертежа, а глобальными. Иначе говоря, изменяя параметры команды в одном чертеже и сохраняя их таким способом, в другом параллельно открытом чертеже, читаю только что измененные параметры.

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

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

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Я немного дополню. Пространство модели - объект и к нему можно добавлять XData/

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Благодарю всех за ответы. В общем, я решил остановиться пока на сохранении своих переменных средствами Visual Studio, как наиболее простом. Использование xData для таких целей вижу неудобным, поскольку объекты могут копироваться и удаляться, таким образом теряются прикрепленные данные. Сохранение пользовательских данных чертежей - код на будущее будет мне полезен, но для других задач. Сейчас не хочу выносить внутренние данные во вкладку, доступную для редактирования пользователем вне самой команды. Странно и неудобно, что нет возможности создавать свои значения по типу системных переменных, сохраняемых в чертеже.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Использование xData для таких целей вижу неудобным, поскольку объекты могут копироваться и удаляться, таким образом теряются прикрепленные данные
Вам же сказали - вы можете хранить XData в самом чертеже. И пример выше дали. Эти данные никуда не денутся

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Использование xData для таких целей вижу неудобным, поскольку объекты могут копироваться и удаляться, таким образом теряются прикрепленные данные
Пространство модели - объект и к нему можно добавлять XData/
Вот как можно потерять пространство модели?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ну как я и сказал - открываете свойства проекта и идете на вкладку "Параметры". Её многие привыкли использовать для локализации (не лучший способ, ИМХО). Там ручками создаем параметры. При этом мы задаем тип данных и значение по умолчанию (которое Phil почему-то не увидел).
При этом VisualStudio создает специальный класс
Дальше уже в коде использовать эти параметры проще простого
Код - C# [Выбрать]
var isCurrent = Properties.Settings.Default.IsCurrent;
При задании новых значений нужно не забывать вызывать метод сохранения, так как само это не происходит
Код - C# [Выбрать]
Properties.Settings.Default.IsCurrent = true;
Properties.Settings.Default.Save();
Еще эти параметры удобно биндить на WPF окна, что сокращает количество кода в разы
Хм, как интересно! То ли раньше этот механизм по-другому работал, то ли я в нём в своё время не до конца разобрался. Спасибо!
Вот мой хелпер для записи в свойства чертежа
Я немного дополню. Пространство модели - объект и к нему можно добавлять XData/
Странно, что никто ещё не посоветовал использовать NamedObjectDictionary. Хотя, на мой взгляд, это самое оптимальное место хранения данных уровня чертежа.

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Странно, что никто ещё не посоветовал использовать NamedObjectDictionary. Хотя, на мой взгляд, это самое оптимальное место хранения данных уровня чертежа.
А можно пример практической реализации? Я пробовал читать и записывать, но не разобрался как, к примеру, записать в словарь числовое значение double

Отмечено как Решение Phil 24-03-2018, 13:02:56

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Странно, что никто ещё не посоветовал использовать NamedObjectDictionary
Почему же никто? Первый комментарий в теме:
Если надо сохранить в чертеж - я бы использовал словари и xRecord

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Один из самых простых и наглядных: https://forums.autodesk.com/t5/net/save-some-variables-into-dwg-file-how-c/td-p/3617358
Ну и, классика: https://google.gik-team.com/?q=autocad+net+namedobjectsdictionary ;)
Обнаружилась некоторая проблема при использовании этого решения... Ниже приведен код.

Последовательность действий, иллюстрирующих проблему:
1. Команда SaveVar. Ввести число, отличное от числа по умолчанию (в начале это "5.555"). Скажем, "777"
2. Любая другая команда (к примеру Line).
3. Команда SaveVar. Ввести число, отличное от числа по умолчанию (теперь это "777"). Скажем, "888"
4. Вызвать команду Undo.
5. Команда ReadVar.

Результат выполнения последней команды будет "5.555", хотя должно бы быть "777"

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5.  
  6. public class MyCommands
  7. {
  8.  
  9.     public void WriteXrecord(Document doc, string dictName, string key, ResultBuffer resbuf)
  10.     {
  11.         Database db = doc.Database;
  12.         using (Transaction tr = db.TransactionManager.StartTransaction())
  13.         {
  14.             DBDictionary NOD =
  15.                 (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
  16.             DBDictionary dict;
  17.             if (NOD.Contains(dictName))
  18.             {
  19.                 dict = (DBDictionary)tr.GetObject(NOD.GetAt(dictName), OpenMode.ForWrite);
  20.             }
  21.             else
  22.             {
  23.                 dict = new DBDictionary();
  24.                 NOD.UpgradeOpen();
  25.                 NOD.SetAt(dictName, dict);
  26.                 tr.AddNewlyCreatedDBObject(dict, true);
  27.             }
  28.             Xrecord xRec = new Xrecord();
  29.             xRec.Data = resbuf;
  30.             dict.SetAt(key, xRec);
  31.             tr.AddNewlyCreatedDBObject(xRec, true);
  32.             tr.Commit();
  33.         }
  34.     }
  35.  
  36.     public ResultBuffer ReadXrecord(Document doc, string dictName, string key)
  37.     {
  38.         Database db = doc.Database;
  39.         using (Transaction tr = db.TransactionManager.StartTransaction())
  40.         {
  41.             DBDictionary NOD =
  42.                 (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
  43.             if (!NOD.Contains(dictName))
  44.                 return null;
  45.             DBDictionary dict = tr.GetObject(NOD.GetAt(dictName), OpenMode.ForRead) as DBDictionary;
  46.             if (dict == null || !dict.Contains(key))
  47.                 return null;
  48.             Xrecord xRec = tr.GetObject(dict.GetAt(key), OpenMode.ForRead) as Xrecord;
  49.             if (xRec == null)
  50.                 return null;
  51.             return xRec.Data;
  52.         }
  53.     }
  54.  
  55.     public void WriteDouble(Document doc, string acDictName, string acKey, double var)
  56.     {
  57.         ResultBuffer acResultBuffer = new ResultBuffer();
  58.         acResultBuffer.Add(new TypedValue((int)DxfCode.ExtendedDataReal, var));
  59.         WriteXrecord(doc, acDictName, acKey, acResultBuffer);
  60.  
  61.     }
  62.  
  63.     public double ReadXDouble(Document doc, string acDictName, string acKey, double acDefault)
  64.     {
  65.         ResultBuffer acResultBuffer = new ResultBuffer();
  66.         acResultBuffer = ReadXrecord(doc, acDictName, acKey);
  67.         if (acResultBuffer != null)
  68.             return (double)acResultBuffer.AsArray()[0].Value;
  69.         else return acDefault;
  70.     }
  71.  
  72.     [CommandMethod("savevar", CommandFlags.Modal)]
  73.     public void MyCommand1()
  74.     {
  75.         Document doc = Application.DocumentManager.MdiActiveDocument;
  76.         double var = ReadXDouble(doc, "dist", "key", 5.555);
  77.  
  78.         PromptDoubleOptions pdo = new PromptDoubleOptions("Введите число");
  79.         pdo.DefaultValue = var;
  80.         PromptDoubleResult pdr = doc.Editor.GetDouble(pdo);
  81.         if (pdr.Status != PromptStatus.OK) return;
  82.  
  83.         WriteDouble(doc, "dist_1", "key_1", pdr.Value);
  84.         Application.ShowAlertDialog("Переменная сохранена");
  85.     }
  86.  
  87.     [CommandMethod("readvar", CommandFlags.Modal)]
  88.     public void MyCommand2()
  89.     {
  90.         Document doc = Application.DocumentManager.MdiActiveDocument;
  91.         double var = ReadXDouble(doc, "dist_1", "key_1", 5.555);
  92.         Application.ShowAlertDialog("Сохраненное число = " + var);
  93.     }
  94. }

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

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

Оффлайн PhilАвтор темы

  • ADN OPEN
  • Сообщений: 47
  • Карма: 0
Почитай: http://adndevblog.typepad.com/autocad/2012/07/undo-removes-updated-dictionary-entry.html

Снимаю шляпу перед вашими знаниями и отзывчивостью! В соответствии с рекомендацией по ссылке скорректировал процедуру записи значения:

Код - C# [Выбрать]
  1.     public void WriteXrecord(Document doc, string dictName, string key, ResultBuffer resbuf)
  2.     {
  3.         Database db = doc.Database;
  4.         using (Transaction tr = db.TransactionManager.StartTransaction())
  5.         {
  6.             DBDictionary NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
  7.             DBDictionary dict;
  8.             if (NOD.Contains(dictName))
  9.             {
  10.                 dict = (DBDictionary)tr.GetObject(NOD.GetAt(dictName), OpenMode.ForWrite);
  11.             }
  12.             else
  13.             {
  14.                 dict = new DBDictionary();
  15.                 NOD.UpgradeOpen();
  16.                 NOD.SetAt(dictName, dict);
  17.                 tr.AddNewlyCreatedDBObject(dict, true);
  18.             }
  19.  
  20.             Xrecord xRec;
  21.             if (dict.Contains(key))
  22.             {
  23.                 // Дополнение к процедуре записи: если ключ существует, обновляем значение существующей xRec
  24.                 xRec = tr.GetObject(dict.GetAt(key), OpenMode.ForWrite) as Xrecord;
  25.                 xRec.Data = resbuf;
  26.             }
  27.             else
  28.             {
  29.                 xRec = new Xrecord();
  30.                 xRec.Data = resbuf;
  31.                 dict.SetAt(key, xRec);
  32.                 tr.AddNewlyCreatedDBObject(xRec, true);
  33.             }
  34.  
  35.             tr.Commit();
  36.         }
  37.     }