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

13/07/2014

Использование объекта DataStorage для хранения настроек

У разработчиков часто возникает вопрос, где хранить настройки приложения либо другую информацию, которая привязана к конкретной модели.

Традиционно для этих целей использовались общие параметры, затем, расширяемая область хранения Extensible Storage. Но у обоих вариантов возникала проблема, какой элемент нужно использовать для хранения параметра или к какому применить расширяемую область. Одним из вариантов – использовать элемент ProjectInfo, содержащий в себе информацию о проекте.

Однако, при совместной работе над проектом часто возникает ситуация, когда один из пользователей заблокировал этот элемент для изменения, например, когда элементарно поменял настройки проекта.

В Revit 2013 API для этих целей появился специальный объект – DataStorage. Объект наследуется от класса Element, а, следовательно, его можно и нужно использовать для хранения расширяемой области хранения.

DataStorage не доступен пользователям. Только через API. А значит, действия пользователя не повлияют на блокировки этого элемента.

Рассмотрим пример использования DataStorage.

Так как для хранения необходимо использовать расширяемую область хранения, то, первым делом необходимо создать схему, которая будет содержать поля, в которых будет храниться ваши настройки.

Код - C#: [Выделить]
  1.  
  2.     public static class AdnCisSampleSchema
  3.     {
  4.         private readonly static Guid schemaId =
  5.             new Guid("B08287CD-BB06-47AC-88E0-705D5411F962");
  6.  
  7.         public static Schema GetSchema()
  8.         {
  9.             //Смотрим, Загружена ли схема в память или нет
  10.             Schema schema = Schema.Lookup(schemaId);
  11.             if (schema != null)
  12.                 return schema; // возвращаем схему, если она уже созадна и загружена
  13.  
  14.             // Создаем схему, если ее еще нет.
  15.             SchemaBuilder schemaBuilder = new SchemaBuilder(schemaId);
  16.  
  17.             // Схема будет содержать одно поле
  18.             // в котором хранится URL
  19.             schemaBuilder
  20.                 .SetSchemaName("MyAddinSettings")
  21.                 .AddSimpleField("SiteURL", typeof (string));
  22.  
  23.             return schemaBuilder.Finish();
  24.         }
  25.     }

 

Создадим две команды. В первой мы запишем в наш объект наши настройки. Во второй, прочитаем записанные настройки.

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

Для удобства, создадим вспомогательный класс, для поиска нашего DataStorage. В случае, если его нет, он будет создан.

Так как DataStorage наследуется от класса Element, то применим старый добрый FilteredElementCollector для поиска элементов с фильтрацией по типу класса:

Код - C#: [Выделить]
  1.             var dataStorages = new FilteredElementCollector(_document)
  2.                 .OfClass(typeof (DataStorage))
  3.                 .OfType<DataStorage>()
  4.                 .ToList();

Данный код вернет нам все элементы типа DataStorage в документе. Объектов может быть несколько. Всегда помните об этом. Из всех надо выбрать именно тот, который нужно вам и который хранит именно ваши настройки.

Это можно сделать, попробовав получить сущность Entity, в которой хранится ваши настройки, т.е. получить сущность с вашей схемой.

Код - C#: [Выделить]
  1.             foreach (var dataStorage in dataStorages)
  2.             {
  3.                 var entity = dataStorage.GetEntity(AdnCisSampleSchema.GetSchema());
  4.                 if (entity != null && entity.IsValid())
  5.                     return dataStorage;
  6.             }

Если объект не найден – создаем новый:

Код - C#: [Выделить]
  1. DataStorage storage = DataStorage.Create(_document);

После того, как мы получили наш объект, мы можем в него записать наши данные.

Для этого нам надо создать объект Entity, и записать туда данные, согласно нашей созданной ранее схеме. Затем, записать эту сущность в объект DataStorage.

Код - C#: [Выделить]
  1.             var dataStorage = GetDataStorage();
  2.  
  3.             Entity entity = new Entity(AdnCisSampleSchema.GetSchema());
  4.  
  5.             entity.Set("SiteURL", url);
  6.  
  7.             dataStorage.SetEntity(entity);

Для чтения наших настроек, нужно также получить объект DataStorage, который хранит наши настройки, взять сущность нашей схемы, и прочитать из нее соответствующее поле.

Код - C#: [Выделить]
  1.             var dataStorage = GetDataStorage(true);
  2.  
  3.             if (dataStorage == null)
  4.                 return null;
  5.  
  6.             var entity = dataStorage.GetEntity(AdnCisSampleSchema.GetSchema());
  7.  
  8.             if (entity == null)
  9.                 return null;
  10.  
  11.             var url = entity.Get<string>("SiteURL");
  12.  
  13.             return url;

Полный код класса для чтения/записи настроек:

Код - C#: [Выделить]
  1.     class AdnSettingsDataStorageHelper
  2.     {
  3.         private readonly Document _document;
  4.  
  5.         public AdnSettingsDataStorageHelper(Document document)
  6.         {
  7.             _document = document;
  8.         }
  9.  
  10.         public void WriteURL(string url)
  11.         {
  12.             var dataStorage = GetDataStorage(true);
  13.  
  14.             Entity entity = new Entity(AdnCisSampleSchema.GetSchema());
  15.  
  16.             entity.Set("SiteURL", url);
  17.  
  18.             dataStorage.SetEntity(entity);
  19.         }
  20.  
  21.         public string ReadURL()
  22.         {
  23.             var dataStorage = GetDataStorage();
  24.  
  25.             if (dataStorage == null)
  26.                 return null;
  27.  
  28.             var entity = dataStorage.GetEntity(AdnCisSampleSchema.GetSchema());
  29.  
  30.             if (entity == null)
  31.                 return null;
  32.  
  33.             var url = entity.Get<string>("SiteURL");
  34.  
  35.             return url;
  36.         }
  37.  
  38.         /// <summary>
  39.         /// метод ищет в документе объект DataStorage,
  40.         /// в котором хранятся наши нстройки.
  41.         /// В случае, если его нет, то он будет создан.
  42.         /// </summary>
  43.         /// <returns></returns>
  44.         private DataStorage GetDataStorage(bool createIfNotExists = false)
  45.         {
  46.             // DataStorage является Element/
  47.             // Для поиска элементов как и прежде используем
  48.             // FilteredElementColector
  49.  
  50.             var dataStorages = new FilteredElementCollector(_document)
  51.                 .OfClass(typeof (DataStorage))
  52.                 .OfType<DataStorage>()
  53.                 .ToList();
  54.  
  55.             foreach (var dataStorage in dataStorages)
  56.             {
  57.                 var entity = dataStorage.GetEntity(AdnCisSampleSchema.GetSchema());
  58.                 if (entity != null && entity.IsValid())
  59.                     return dataStorage;
  60.             }
  61.  
  62.             if (!createIfNotExists)
  63.                 return null;
  64.  
  65.             // попадаем сюда, если объект не был найден.
  66.             // Создаем новый
  67.             DataStorage storage = DataStorage.Create(_document);
  68.  
  69.             return storage;
  70.         }
  71.     }

И коды команд для сохранения и чтения настроек. Код довольно прост.

Сохранение настроек:

Код - C#: [Выделить]
  1.     [Transaction(TransactionMode.Manual)]
  2.     public class CommandWriteSettings : IExternalCommand
  3.     {
  4.         public Result Execute(
  5.           ExternalCommandData commandData,
  6.           ref string message,
  7.           ElementSet elements)
  8.         {
  9.             var doc = commandData.Application.ActiveUIDocument.Document;
  10.  
  11.             using (Transaction trans = new Transaction(doc,"Сохранение настроек"))
  12.             {
  13.                 trans.Start();
  14.  
  15.                 AdnSettingsDataStorageHelper settingsDataStorageHelper =
  16.                     new AdnSettingsDataStorageHelper(doc);
  17.  
  18.                 settingsDataStorageHelper.WriteURL("http://adn-cis.org");
  19.  
  20.                 var res = trans.Commit();
  21.  
  22.                 if (res == TransactionStatus.Committed)
  23.                     TaskDialog.Show("ADN-CIS", "Настройки сохранены");
  24.             }
  25.  
  26.             return Result.Succeeded;
  27.         }
  28.     }

И чтение:

Код - C#: [Выделить]
  1.     [Transaction(TransactionMode.Manual)]
  2.     public class CommandReadSettings : IExternalCommand
  3.     {
  4.         public Result Execute(
  5.             ExternalCommandData commandData,
  6.             ref string message,
  7.             ElementSet elements)
  8.         {
  9.             var doc = commandData.Application.ActiveUIDocument.Document;
  10.  
  11.             AdnSettingsDataStorageHelper settingsDataStorageHelper =
  12.                    new AdnSettingsDataStorageHelper(doc);
  13.  
  14.             var url = settingsDataStorageHelper.ReadURL();
  15.  
  16.             if (url == null)
  17.                 TaskDialog.Show("ADN-CIS", "Настройки не заданы");
  18.  
  19.             else
  20.                 TaskDialog.Show("ADN-CIS", string.Format("Значение URL: {0}", url));
  21.                     
  22.            
  23.  
  24.             return Result.Succeeded;
  25.         }
  26.     }

В результате выполнения команды чтения (после записи), увидим окно с результатом наших настроек:

 

Полный исходный код с проектом для Visual Studio, можете скачать на GitHub, либо архивом.

Автор: Виктор Чекалин
Автор перевода: Виктор Чекалин

Обсуждение: http://adn-cis.org/forum/index.php?topic=854

Опубликовано 13.07.2014
Отредактировано 13.07.2014 в 23:58:31