2. Менеджер текстовых стилей

Дата публикации: 29.06.2011
Дата редактирования: 04.07.2011
Состояние: в стадии разработки 
Целевая версия: AutoCAD 2009

    Открываем в AutoCAD окно редактора текстовых стилей и смотрим какие настройки там имеются:

    На основании того, что мы видим, давайте создадим класс, представляющий собой настройки текстовых стилей. Визуально он будет выглядеть так:

    Как видим - запутаться в этом классе сложно, ибо все его свойства называются так же, как сами настройки в выше показанном диалоговом окне (имена свойств могут незначительно отличаться от их оконных аналогов, однако их отождествление не должно вызывать трудностей). Помимо свойств, хранящих настройки текстового стиля, наш класс имеет несколько методов:
  • Clone - создание точной копии объекта настроек (реализация интерфейса ICloneable<TextStyleInfo>)
  • Equals - проверка на то, являются ли два объекта TextStyleInfo одинаковыми: сравниваются все настройки. Этот метод определён в интерфейсе  IEquatable<TextStyleInfo>.
  • Методы GetShema, WriteXml и ReadXml определены в составе интерфейса IXmlSerializable - с их помощью можно легко сериализовать объект настроек в xml-формат, либо наоборот - выполнить десериализацию.
  • GetXElement - дополнительный метод, с помощью которого можно сериализовать настройки в объект XElement - очень удобный класс! Я вообще с xml предпочитаю работать только через LINQ to XML. Далее, в примерах использования менеджера текстовых стилей продемонстрируем, как легко выполнять сериализацию/десериализацию с последующим чтением/записью настроек из файла или в файл.
  • Load - инициализация настроек на основании значений, полученных либо из внешнего xml-файла, либо из указанного xml-элемента
  • Save - сохранение настроек в новый xml-файл
   
Все ресурсы, требующие локализации, мы сразу будем выносить в отдельный resx-файл. По завершению написания кода класса TextStyleInfo, содержимое resx-файла будет таким (визуальное представление):


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

Класс TextStyleInfo (объект настроек текстового стиля)

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Xml.Serialization;
   6:  using System.Xml.Linq;
   7:  using System.IO;
   8:  using System.Xml;
   9:   
  10:  namespace Bushman.AutoCAD.Styles {
  11:      /// <summary>
  12:      /// Класс, инкапсулирующий в себе настройки объекта текстового стиля
  13:      /// </summary>
  14:      public sealed class TextStyleInfo : IStyleSettings<TextStyleInfo> {
  15:          /// <summary>
  16:          /// Имя текстового стиля
  17:          /// </summary>
  18:          public string Name { get; set; }
  19:          /// <summary>
  20:          /// Имя шрифта, используемого в текстовом стиле
  21:          /// </summary>
  22:          public string FontName { get; set; }
  23:          /// <summary>
  24:          /// Имя большого шрифта. Если указано значение "" - большой шрифт
  25:          /// не используется
  26:          /// </summary>
  27:          public string BigFontName { get; set; }
  28:          /// <summary>
  29:          /// Аннотативный
  30:          /// </summary>
  31:          public bool Annotative { get; set; }
  32:          /// <summary>
  33:          /// Ориентация относительно листа
  34:          /// </summary>
  35:          public bool OrientationToLayout { get; set; }
  36:          /// <summary>
  37:          /// Высота текста
  38:          /// </summary>
  39:          public double TextHeight { get; set; }
  40:          /// <summary>
  41:          /// Коэффициент сжатия
  42:          /// </summary>
  43:          public double WidthFactor { get; set; }
  44:          /// <summary>
  45:          /// Угол наклона текста (в градусах, относительно вертикальной 
  46:          /// линии по часовой стрелке)
  47:          /// </summary>
  48:          public double ObliqueAngle { get; set; }
  49:          /// <summary>
  50:          /// Размещать текст "головой вниз", т.е. развёрнутым на 180 градусов
  51:          /// </summary>
  52:          public bool UpsideDown { get; set; }
  53:          /// <summary>
  54:          /// Направление печати. True - справа налево. False - слева направо.
  55:          /// </summary>
  56:          public bool Backwards { get; set; }
  57:          /// <summary>
  58:          /// Размещать строку текста вертикально
  59:          /// </summary>
  60:          public bool Vertical { get; set; }
  61:   
  62:          /// <summary>
  63:          /// Создать точную копию объекта настроек
  64:          /// </summary>
  65:          /// <returns>Копия объекта</returns>
  66:          public TextStyleInfo Clone() {
  67:              TextStyleInfo x = new TextStyleInfo();
  68:              x.Annotative = Annotative;
  69:              x.Backwards = Backwards;
  70:              x.BigFontName = BigFontName;
  71:              x.FontName = FontName;
  72:              x.Name = Name;
  73:              x.ObliqueAngle = ObliqueAngle;
  74:              x.OrientationToLayout = OrientationToLayout;
  75:              x.TextHeight = TextHeight;
  76:              x.UpsideDown = UpsideDown;
  77:              x.Vertical = Vertical;
  78:              x.WidthFactor = WidthFactor;
  79:              return x;
  80:          }
  81:          /// <summary>
  82:          /// Получить xsd-схему
  83:          /// </summary>
  84:          /// <returns>Всегда возвращается null</returns>
  85:          public System.Xml.Schema.XmlSchema GetSchema() {
  86:              return null;
  87:          }
  88:          /// <summary>
  89:          /// Инициализировать объект настроек текстовых стилей на
  90:          /// основе xml-данных
  91:          /// </summary>
  92:          /// <param name="reader">Объект, с помощью которого читаем xml-настройки</param>
  93:          public void ReadXml(System.Xml.XmlReader reader) {
  94:              XElement xml = XElement.Load(reader);
  95:              this.Annotative = bool.Parse(xml.Element("Annotative").Value.Trim());
  96:              this.Backwards = bool.Parse(xml.Element("Backwards").Value.Trim());
  97:              this.BigFontName = xml.Element("BigFontName").Value.Trim();
  98:              this.FontName = xml.Element("FontName").Value.Trim();
  99:              this.Name = xml.Attribute("Name").Value.Trim();
 100:              this.ObliqueAngle = double.Parse(xml.Element("ObliqueAngle").Value.Trim());
 101:              this.OrientationToLayout = bool.Parse(xml.Element("OrientationToLayout").Value.Trim());
 102:              this.TextHeight = double.Parse(xml.Element("TextHeight").Value.Trim());
 103:              this.UpsideDown = bool.Parse(xml.Element("UpsideDown").Value.Trim());
 104:              this.Vertical = bool.Parse(xml.Element("Vertical").Value.Trim());
 105:              this.WidthFactor = double.Parse(xml.Element("WidthFactor").Value.Trim());
 106:          }
 107:          /// <summary>
 108:          /// Экспорт настроек в xml
 109:          /// </summary>
 110:          /// <param name="writer">Во что пишем</param>
 111:          public void WriteXml(System.Xml.XmlWriter writer) {
 112:              //Имя стиля записываем в атрибут корневого xml-элемента
 113:              writer.WriteAttributeString("Name", Name);
 114:              //Каждую настройку записываем в отдельный xml-элемент
 115:              writer.WriteElementString("FontName", FontName);
 116:              writer.WriteElementString("BigFontName", BigFontName);
 117:              writer.WriteElementString("Annotative", Annotative.ToString());
 118:              writer.WriteElementString("OrientationToLayout", OrientationToLayout.ToString());
 119:              writer.WriteElementString("TextHeight", TextHeight.ToString());
 120:              writer.WriteElementString("WidthFactor", WidthFactor.ToString());
 121:              writer.WriteElementString("ObliqueAngle", ObliqueAngle.ToString());
 122:              writer.WriteElementString("UpsideDown", UpsideDown.ToString());
 123:              writer.WriteElementString("Backwards", Backwards.ToString());
 124:              writer.WriteElementString("Vertical", Vertical.ToString());
 125:          }
 126:          /// <summary>
 127:          /// Проверка на то, является ли содержимое двух объектов настроек
 128:          /// текстовых стилей идентичными.
 129:          /// </summary>
 130:          /// <param name="other">Объект настроек текстовых стилей, с которым
 131:          /// должно производиться сравнение</param>
 132:          /// <returns>true - содержимое настроек одинаковое; false - разное</returns>
 133:          public bool Equals(TextStyleInfo other) {
 134:              return
 135:                  (this.Name.ToUpper() == other.Name.ToUpper()) &&                
 136:                  (this.BigFontName.ToUpper() == other.BigFontName.ToUpper()) &&
 137:                  (this.FontName.ToUpper() == other.FontName.ToUpper()) && 
 138:                  (this.Annotative == other.Annotative) &&
 139:                  (this.Backwards == other.Backwards) &&
 140:                  (this.ObliqueAngle == other.ObliqueAngle) &&
 141:                  (this.OrientationToLayout == other.OrientationToLayout) &&
 142:                  (this.TextHeight == other.TextHeight) &&
 143:                  (this.UpsideDown == other.UpsideDown) &&
 144:                  (this.Vertical == other.Vertical) &&
 145:                  (this.WidthFactor == other.WidthFactor);
 146:          }
 147:          /// <summary>
 148:          /// Упаковать настройки в виде объекта XElement
 149:          /// </summary>
 150:          /// <param name="encoding">Кодировка (рекомендую UTF8)</param>
 151:          /// <returns>Возвращается объект XElement, в котором упакованы 
 152:          /// настройки текстового стиля</returns>
 153:          public XElement GetXElement(Encoding encoding) {
 154:              XElement xml;
 155:              using (MemoryStream ms = new MemoryStream()) {
 156:                  XmlTextWriter writer = new XmlTextWriter(ms, encoding);
 157:                  writer.Formatting = Formatting.Indented;
 158:                  XmlSerializer serializer = new XmlSerializer(this.GetType());
 159:                  serializer.Serialize(writer, this);
 160:                  writer.Flush();
 161:                  ms.Position=0;
 162:                  xml = XElement.Load(XmlReader.Create(ms));
 163:                  writer.Close();
 164:                  ms.Close();
 165:              }
 166:              return xml;
 167:          }
 168:   
 169:          /// <summary>
 170:          /// Загрузить настройки из xml-файла
 171:          /// </summary>
 172:          /// <param name="xmlFileName">Имя файла, в котором сериализованы настройки</param>
 173:          public void Load(string xmlFileName) {
 174:              if (!File.Exists(xmlFileName))
 175:                  throw new FileNotFoundException(string.Format(TextStyleMngRes.FileNotFound, xmlFileName));
 176:              ReadXml(XElement.Load(xmlFileName).CreateReader());
 177:          }
 178:          /// <summary>
 179:          /// Загрузить настройки из xml-элемента
 180:          /// </summary>
 181:          /// <param name="xml">xml-элемент, в котором содержатся настройки</param>
 182:          public void Load(XElement xml) {
 183:              ReadXml(xml.CreateReader());
 184:          }
 185:          /// <summary>
 186:          /// Сохранить настройки в новый xml-файл
 187:          /// </summary>
 188:          /// <param name="xmlFileName">Имя файла</param>
 189:          /// <param name="encoding">Кодировка (рекомендуется UTF8)</param>
 190:          public void Save(string xmlFileName, Encoding encoding) {
 191:              XElement xml = GetXElement(encoding);
 192:              xml.Save(xmlFileName);
 193:          }
 194:      }
 195:  }

    Как видим - всё очень просто: наш класс содержит в себе значения настроек интересующего нас типа стилей (в данном случае - текстового) и посредством реализации интерфейса IStyleSettings<TextStyleInfo> предоставляет некоторый дополнительный функционал, который нам может понадобиться в работе с этим классом. 

    Теперь нам нужно написать сам менеджер управления текстовыми стилями. Этот класс должен реализовывать созданный нами ранее интерфейс IStyleManager<T, V> . Обратите внимание, что вместо T и V нашему обобщённому интерфейсу мы уже должны указывать конкретные типы - TextStyleTableRecord и TextStyleInfo, поскольку мы пишем менеджер именно текстовых стилей.

Класс TextStyleManager : IStyleManager<TextStyleTableRecord, TextStyleInfo> (менеджер текстовых стилей)

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Xml.Linq;
   6:  using System.IO;
   7:  using System.Reflection;
   8:  //Acad
   9:  using acad = Autodesk.AutoCAD.ApplicationServices.Application;
  10:  using Autodesk.AutoCAD.GraphicsInterface;
  11:  using Autodesk.AutoCAD.Interop.Common;
  12:  using Autodesk.AutoCAD.ApplicationServices;
  13:  using Autodesk.AutoCAD.Geometry;
  14:  using Autodesk.AutoCAD.LayerManager;
  15:  using Autodesk.AutoCAD.Colors;
  16:  using Autodesk.AutoCAD.DatabaseServices;
  17:  using Autodesk.AutoCAD.EditorInput;
  18:  using Autodesk.AutoCAD.Runtime;
  19:  using Autodesk.AutoCAD.Interop;
  20:  //Bushman
  21:  using Bushman.AutoCAD.Common;
  22:   
  23:  namespace Bushman.AutoCAD.Styles
  24:  {
  25:      /// <summary>
  26:      /// Менеджер табличных стилей AutoCAD
  27:      /// </summary>
  28:      public sealed class TextStyleManager : IStyleManager<TextStyleTableRecord, TextStyleInfo>
  29:      {
  30:          Database db;
  31:          /// <summary>
  32:          /// Конструктор класса
  33:          /// </summary>
  34:          /// <param name="targetDb">База данных чертежа, со стилями которой должен работать
  35:          /// менеджер стилей</param>
  36:          public TextStyleManager(Database targetDb)
  37:          {
  38:              TargetDb = targetDb;
  39:          }
  40:          /// <summary>
  41:          /// Получение примитивов, использующих указанный стиль
  42:          /// </summary>
  43:          /// <param name="styleName">Имя стиля</param>
  44:          /// <returns>Возвращается коллекция идентификаторов примитивов</returns>
  45:          public ObjectId[] GetDependentPrimitives(string styleName)
  46:          {
  47:              return GetDependentPrimitives(new string[] { styleName })[styleName.Trim().ToUpper()];
  48:          }
  49:          /// <summary>
  50:          /// Получение всех примитивов, использующих стиль, имя которого присутствует в указанном 
  51:          /// перечне стилей.
  52:          /// В результате формируется общий массив идентификаторов таких объектов.
  53:          /// </summary>
  54:          /// <param name="styleNames">Массив имён стилей</param>
  55:          /// <returns>Возвращается словарь, каждая запись которого содержит в себе массивы 
  56:          /// идентификаторов. В качестве ключа для каждого массива используется имя 
  57:          /// соответствующего стиля</returns>
  58:          public Dictionary<string, ObjectId[]> GetDependentPrimitives(string[] styleNames)
  59:          {
  60:              //Из указанного массива имён текстовых стилей выбираем те, которые действительно имеются
  61:              //в базе данных чертежа
  62:              styleNames = styleNames.Where(n => Exists(n)).Select(n => n.Trim().ToUpper()).ToArray();
  63:   
  64:              //Если стили, подлежащие уничтожению на найдены - возвращаем null
  65:              if (styleNames.Length == 0)
  66:                  return null;
  67:   
  68:              //Результирующая выборка (будет возвращена из метода)
  69:              Dictionary<string, List<ObjectId>> result = new Dictionary<string, List<ObjectId>>();
  70:   
  71:              foreach (string item in styleNames)
  72:                  result.Add(item.Trim().ToUpper(), new List<ObjectId>());
  73:   
  74:              //Типы, объекты которых мы должны проверить
  75:              Type[] types = new Type[] { typeof(DBText), typeof(MText), typeof(IAcadText), 
  76:                  typeof(IAcadMText), typeof(DimStyleTableRecord), typeof(MLeaderStyle), 
  77:                  typeof(TableStyle), typeof(Table)
  78:              /*
  79:               * Эти типы нет необходимости указывать отдельно, т.к. они наследуются от DBText, 
  80:               * а его мы уже указали:             
  81:               * typeof(AttributeDefinition), 
  82:               * typeof(AttributeReference)
  83:               */
  84:              };
  85:   
  86:              //Создаём объект-поисковик...
  87:              DBSearcher seacher = new DBSearcher(TargetDb);
  88:   
  89:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
  90:                  //Получаем искомый наборы примитивов для каждого из указанных стилей
  91:                  seacher.GetPrimitives().Where(n => types.Contains(t.GetObject(n, OpenMode.ForRead)
  92:                      .GetType())).All(n => { Fill(n, result); return true; });
  93:   
  94:              //Теперь на основе Dictionary<string, List<ObjectId>> нужно получить объект
  95:              //Dictionary<string, ObjectId[]>
  96:              Dictionary<string, ObjectId[]> dict = new Dictionary<string, ObjectId[]>();
  97:   
  98:              foreach (var item in result)
  99:                  dict.Add(item.Key, item.Value.ToArray());
 100:   
 101:              //Возвращаю результат
 102:              return dict;
 103:          }
 104:   
 105:          /// <summary>
 106:          /// Проверка на то, следует ли некоторый примитив включить в состав конечной выборки (массив
 107:          /// примитивов, использующих один из указанных текстовых стилей)
 108:          /// </summary>
 109:          /// <param name="id">Идентификатор объекта, подлежащего проверке</param>
 110:          /// <param name="dict">Имена текстовых стилей, на предмет использования которых проверяется
 111:          /// объект</param>
 112:          private void Fill(ObjectId id, Dictionary<string, List<ObjectId>> dict)
 113:          {
 114:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 115:              {
 116:                  DBObject item = t.GetObject(id, OpenMode.ForRead);
 117:                  //Если это размерный стиль
 118:                  if (item is DimStyleTableRecord)
 119:                  {
 120:                      DimStyleTableRecord x = (DimStyleTableRecord)item;
 121:   
 122:                      string styleName = ((TextStyleTableRecord)t.GetObject(x.Dimtxsty,
 123:                          OpenMode.ForRead)).Name.Trim().ToUpper();
 124:   
 125:                      if (dict.Keys.Contains(styleName))
 126:                          dict[styleName].Add(item.ObjectId);
 127:                      return;
 128:                  }
 129:                  //Если это стиль мультивыноски
 130:                  else if (item is MLeaderStyle)
 131:                  {
 132:                      MLeaderStyle x = (MLeaderStyle)item;
 133:   
 134:                      string styleName = ((TextStyleTableRecord)t.GetObject(x.TextStyleId,
 135:                          OpenMode.ForRead)).Name.Trim().ToUpper();
 136:   
 137:                      if (dict.Keys.Contains(styleName))
 138:                          dict[styleName].Add(item.ObjectId);
 139:                      return;
 140:                  }
 141:                  //Если это стиль таблиц
 142:                  else if (item is TableStyle)
 143:                  {
 144:                      TableStyle ts = (TableStyle)item;
 145:   
 146:                      //По умолчанию каждый табличный стиль определяет в своём составе три стиля ячеек:
 147:                      //_TITLE, _HEADER и _DATA. В дополнение к этим стилям, пользователь может определить
 148:                      //свои. Каждый из стилей ячеек определяет в своём составе (помимо всего прочего) то, 
 149:                      //какой ТЕКСТОВЫЙ СТИЛЬ должен использоваться в ячейках, использующих этот СТИЛЬ
 150:                      //ЯЧЕЕК.
 151:   
 152:                      //Проверяем каждый имеющийся стиль ячеек на предмет того, какой текстовый стиль
 153:                      //обозначен в их настройках к использованию для ячеек таблицы
 154:                      foreach (string cellStyle in ts.CellStyles)
 155:                      {
 156:                          string styleName = GetStyle(ts.TextStyle(cellStyle)).Name.Trim().ToUpper();
 157:                          if (dict.Keys.Contains(styleName) && !dict[styleName].Contains(item.ObjectId)) {
 158:                              dict[styleName].Add(item.ObjectId);
 159:                              return;
 160:                          }
 161:                      }
 162:                  }
 163:                  //Если это однострочный текст
 164:                  else if (item is DBText)
 165:                  {
 166:                      DBText txt = (DBText)item;
 167:                      string styleName = ((TextStyleTableRecord)t.GetObject(txt.TextStyle,
 168:                          OpenMode.ForRead)).Name.Trim().ToUpper();
 169:   
 170:                      if (dict.Keys.Contains(styleName))
 171:                          dict[styleName].Add(item.ObjectId);
 172:                      return;
 173:                  }
 174:                  //Если это многострочный текст
 175:                  else if (item is MText)
 176:                  {
 177:                      MText txt = (MText)item;
 178:                      string styleName = ((TextStyleTableRecord)t.GetObject(txt.TextStyle,
 179:                          OpenMode.ForRead)).Name.Trim().ToUpper();
 180:   
 181:                      if (dict.Keys.Contains(styleName))
 182:                          dict[styleName].Add(item.ObjectId);
 183:                      return;
 184:                  }
 185:                  //Если это примитив, реализующий интерфейс IAcadText
 186:                  else if (item is IAcadText)
 187:                  {
 188:                      IAcadText txt = (IAcadText)item;
 189:   
 190:                      string styleName = GetStyle(txt.StyleName).Name.Trim().ToUpper();
 191:   
 192:                      if (dict.Keys.Contains(styleName))
 193:                          dict[styleName].Add(item.ObjectId);
 194:                      return;
 195:                  }
 196:                  //Если это примитив, реализующий интерфейс IAcadMText
 197:                  else if (item is IAcadMText)
 198:                  {
 199:                      IAcadMText txt = (IAcadMText)item;
 200:   
 201:                      string styleName = GetStyle(txt.StyleName).Name.Trim().ToUpper();
 202:   
 203:                      if (dict.Keys.Contains(styleName))
 204:                          dict[styleName].Add(item.ObjectId);
 205:                      return;
 206:                  }
 207:                  //Если это таблица... Стиль текста может быть назначен целому столбцу, строке или же 
 208:                  //отдельной ячейке. Поэтому проверяем все эти варианты.
 209:                  else if (item is Table)
 210:                  {
 211:                      Table table = (Table)item;
 212:   
 213:                      //Сначала проверяю, какие стили текста назначены столбцам. ПОЧЕМУ-ТО ВСЕГДА 
 214:                      //ПОЛУЧАЮ "", НЕ СМОТРЯ НА ТО, ЧТО СТОЛБЦУ МОЖЕТ БЫТЬ НАЗНАЧЕН КОНКТЕТНЫЙ СТИЛЬ ТЕКСТА
 215:                      for (int i = 0; i < table.NumColumns; i++)
 216:                      {
 217:                          string styleName = table.GetCellStyle(-1, i).ToUpper().Trim();
 218:                          if (dict.Keys.Contains(styleName) && !dict[styleName].Contains(item.ObjectId)) {
 219:                              dict[styleName].Add(item.ObjectId);
 220:                              return;
 221:                          }
 222:                      }
 223:   
 224:                      //Теперь проверяю, какие стили текста назначены строкам. ПОЧЕМУ-ТО ВСЕГДА 
 225:                      //ПОЛУЧАЮ "", НЕ СМОТРЯ НА ТО, ЧТО СТРОКЕ МОЖЕТ БЫТЬ НАЗНАЧЕН КОНКТЕТНЫЙ СТИЛЬ ТЕКСТА 
 226:                      for (int i = 0; i < table.NumRows; i++)
 227:                      {
 228:                          string styleName = table.GetCellStyle(i, -1).ToUpper().Trim();
 229:                          if (dict.Keys.Contains(styleName) && !dict[styleName].Contains(item.ObjectId)) {
 230:                              dict[styleName].Add(item.ObjectId);
 231:                              return;
 232:                          }
 233:                      }
 234:                      //Анализируем каждую ячейку таблицы
 235:                      //Цикл по столбцам
 236:                      for (int i = 0; i < table.NumColumns; i++)
 237:                      {
 238:                          //Цикл по строкам
 239:                          for (int k = 0; k < table.NumRows; k++)
 240:                          {
 241:                              //Анализируем конкретную ячейку таблицы
 242:                              string styleName = table.GetCellStyle(k, i).ToUpper().Trim();
 243:                              if (dict.Keys.Contains(styleName) && !dict[styleName].Contains(item.ObjectId)) {
 244:                                  dict[styleName].Add(item.ObjectId);
 245:                                  return;
 246:                              }
 247:                          }
 248:   
 249:                      }
 250:                  }
 251:                  else
 252:                      throw new NotImplementedException();
 253:              }
 254:          }
 255:   
 256:          /// <summary>
 257:          /// Переименовать стиль
 258:          /// </summary>
 259:          /// <param name="oldStyleName">Старое имя стиля</param>
 260:          /// <param name="newStyleName">Новое имя стиля</param>
 261:          /// <returns>Возвращается идентификатор переименованного стиля. Если искомый стиль не найден -
 262:          /// возвращается null</returns>
 263:          public ObjectId Rename(string oldStyleName, string newStyleName)
 264:          {
 265:              if (Exists(newStyleName))
 266:                  throw new System.Exception(string.Format(TextStyleMngRes.StyleAlredyExists,
 267:                      newStyleName));
 268:              ObjectId result;
 269:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 270:              {
 271:                  TextStyleTable txtb = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 272:                      OpenMode.ForRead);
 273:                  TextStyleTableRecord rec = (TextStyleTableRecord)t.GetObject(txtb[oldStyleName],
 274:                      OpenMode.ForWrite);
 275:                  rec.Name = newStyleName;
 276:                  t.Commit();
 277:                  result = rec.ObjectId;
 278:              }
 279:              return result;
 280:          }
 281:          /// <summary>
 282:          /// Создаёт в базе данных чертежа новый стиль, после чего сразу же инициализирует его значениями, 
 283:          /// переданными через параметр метода.
 284:          /// </summary>
 285:          /// <param name="styleSettings">Набор значений, которыми должен быть инициализирован объект 
 286:          /// стиля</param>
 287:          /// <returns>Возвращается идентификатор добавленного в чертёж стиля</returns>
 288:          public ObjectId CreateNew(TextStyleInfo styleSettings)
 289:          {
 290:              if (Exists(styleSettings.Name)) throw new System
 291:      .Exception(string.Format(TextStyleMngRes.StyleAlredyExists, styleSettings));
 292:   
 293:              TextStyleTableRecord ts = new TextStyleTableRecord();
 294:   
 295:              //По умолчанию выставляю следующие настройки
 296:              ts.Name = styleSettings.Name;
 297:              ts.FileName = styleSettings.FontName;
 298:              ts.Annotative = styleSettings.Annotative ? AnnotativeStates.True : AnnotativeStates.False;
 299:              ts.ObliquingAngle = styleSettings.ObliqueAngle * Math.PI / 180;
 300:              ts.SetPaperOrientation(styleSettings.OrientationToLayout);
 301:              ts.BigFontFileName = styleSettings.BigFontName;
 302:              ts.FlagBits = (byte)0;
 303:              ts.FlagBits += styleSettings.UpsideDown ? (byte)2 : (byte)0;
 304:              ts.FlagBits += styleSettings.Backwards ? (byte)4 : (byte)0;
 305:              ts.TextSize = styleSettings.TextHeight;
 306:              ts.XScale = styleSettings.WidthFactor;
 307:              ts.IsVertical = styleSettings.Vertical;
 308:   
 309:              //Запускаю транзакцию
 310:              using (Transaction trs = TargetDb.TransactionManager.StartTransaction())
 311:              {
 312:                  try
 313:                  {
 314:                      //Добавляю созданный стиль в базу данных
 315:                      TextStyleTable tStyles = (TextStyleTable)trs.GetObject(TargetDb.TextStyleTableId,
 316:                          OpenMode.ForRead);
 317:                      tStyles.UpgradeOpen();
 318:                      tStyles.Add(ts);
 319:                      trs.AddNewlyCreatedDBObject(ts, true);
 320:   
 321:                      //А теперь задаю те настройки, которые указаны в параметре
 322:                      SetSettings(ts.Name, styleSettings);
 323:   
 324:                      //Завершаю транзакцию, сохраняя все изменения
 325:                      trs.Commit();
 326:                  }
 327:                  catch { }
 328:              }
 329:              return ts.ObjectId;
 330:          }
 331:          /// <summary>
 332:          /// Получить текущие настройки стиля
 333:          /// </summary>
 334:          /// <param name="styleName">Имя стиля</param>
 335:          /// <returns>Возвращается объект, представляющий собой настройки стиля</returns>
 336:          public TextStyleInfo GetSettings(string styleName)
 337:          {
 338:              TextStyleInfo data = new TextStyleInfo();
 339:              TextStyleTableRecord ts = GetStyle(styleName);
 340:   
 341:              data.Name = ts.Name;
 342:              data.FontName = ts.FileName;
 343:              data.Annotative = ts.Annotative == AnnotativeStates.True ? true : false;
 344:              data.ObliqueAngle = ts.ObliquingAngle / (Math.PI / 180);
 345:              data.OrientationToLayout = ts.PaperOrientation == PaperOrientationStates.True ? true : false;
 346:              data.BigFontName = ts.BigFontFileName;
 347:              data.UpsideDown = (ts.FlagBits & 0x02) == 2 ? true : false;
 348:              data.Backwards = (ts.FlagBits & 0x04) == 4 ? true : false;
 349:   
 350:              data.TextHeight = ts.TextSize;
 351:              data.WidthFactor = ts.XScale;
 352:              data.Vertical = ts.IsVertical;
 353:   
 354:              return data;
 355:          }
 356:          /// <summary>
 357:          /// Получить текущие настройки стиля
 358:          /// </summary>
 359:          /// <param name="styleId">Идентификатор стиля</param>
 360:          /// <returns>Возвращается объект, представляющий собой настройки стиля</returns>
 361:          public TextStyleInfo GetSettings(ObjectId styleId)
 362:          {
 363:              return GetSettings(GetStyle(styleId).Name);
 364:          }
 365:          /// <summary>
 366:          /// Изменить настройки стиля
 367:          /// </summary>
 368:          /// <param name="styleName">имя редактируемого стиля</param>
 369:          /// <param name="settings">Объект, представляющий собой настройки которые должны быть назначены 
 370:          /// стилю.</param>
 371:          public void SetSettings(string styleName, TextStyleInfo settings)
 372:          {
 373:              if (Exists(styleName))
 374:                  using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 375:                  {
 376:                      TextStyleTable tst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 377:                          OpenMode.ForRead);
 378:                      TextStyleTableRecord ts = (TextStyleTableRecord)t.GetObject(tst[styleName],
 379:                          OpenMode.ForWrite);
 380:   
 381:                      if (settings.Name != styleName && Exists(settings.Name))
 382:                          throw new System.Exception(string.Format(TextStyleMngRes.StyleAlredyExists,
 383:                              settings.Name));
 384:                      ts.Name = settings.Name;
 385:                      ts.FileName = settings.FontName;
 386:                      ts.Annotative = settings.Annotative ? AnnotativeStates.True : AnnotativeStates.False;
 387:                      ts.ObliquingAngle = settings.ObliqueAngle * Math.PI / 180;
 388:                      ts.SetPaperOrientation(settings.OrientationToLayout);
 389:                      ts.BigFontFileName = settings.BigFontName;
 390:                      ts.FlagBits = (byte)0;
 391:                      ts.FlagBits += settings.UpsideDown ? (byte)2 : (byte)0;
 392:                      ts.FlagBits += settings.Backwards ? (byte)4 : (byte)0;
 393:                      ts.TextSize = settings.TextHeight;
 394:                      ts.XScale = settings.WidthFactor;
 395:                      ts.IsVertical = settings.Vertical;
 396:   
 397:                      t.Commit();
 398:                  }
 399:          }
 400:          /// <summary>
 401:          /// База данных чертежа, со стилями которой должен работать менеджер
 402:          /// </summary>
 403:          public Database TargetDb
 404:          {
 405:              get { return db; }
 406:              private set { db = value; }
 407:          }
 408:          /// <summary>
 409:          /// Проверка на то, существует ли в чертеже стиль с указанным именем
 410:          /// </summary>
 411:          /// <param name="styleName">Имя стиля, поиск которого выполняется</param>
 412:          /// <returns>True - стиль с указанным именем существует в базе данных чертежа; 
 413:          /// False - не существует</returns>
 414:          public bool Exists(string styleName)
 415:          {
 416:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 417:              {
 418:                  TextStyleTable tst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 419:                      OpenMode.ForRead);
 420:                  return tst.Has(styleName);
 421:              }
 422:          }
 423:          /// <summary>
 424:          /// Получить стиль из базы данных чертежа по его имени
 425:          /// </summary>
 426:          /// <param name="styleName">Имя искомого стиля</param>
 427:          /// <returns>Возвращается объект стиля. Если стиль не найден - возвращается null</returns>
 428:          public TextStyleTableRecord GetStyle(string styleName)
 429:          {
 430:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 431:              {
 432:                  TextStyleTable tst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 433:                      OpenMode.ForRead);
 434:                  return (TextStyleTableRecord)t.GetObject(tst[styleName], OpenMode.ForRead);
 435:              }
 436:          }
 437:          /// <summary>
 438:          /// Получить стиль из базы данных чертежа по его идентификатору
 439:          /// </summary>
 440:          /// <param name="styleName">Идентификатор искомого стиля</param>
 441:          /// <returns>Возвращается объект стиля. Если стиль не найден - возвращается null</returns>
 442:          public TextStyleTableRecord GetStyle(ObjectId styleId)
 443:          {
 444:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 445:              {
 446:                  return (TextStyleTableRecord)t.GetObject(styleId, OpenMode.ForRead);
 447:              }
 448:          }
 449:          /// <summary>
 450:          /// Получить все стили, имеющиеся в базе данных чертежа
 451:          /// </summary>
 452:          /// <returns>Возвращается массив объектов стилей</returns>
 453:          public TextStyleTableRecord[] GetStyles()
 454:          {
 455:              TextStyleTableRecord[] x;
 456:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 457:              {
 458:                  TextStyleTable tst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 459:                      OpenMode.ForRead);
 460:                  x = tst.Cast<ObjectId>().Select(n => (TextStyleTableRecord)t.GetObject(n,
 461:                      OpenMode.ForRead)).ToArray();
 462:              }
 463:              return x;
 464:          }
 465:          /// <summary>
 466:          /// Импорт стиля из другого чертежа
 467:          /// </summary>
 468:          /// <param name="database">База данных (объект класса Database), 
 469:          /// из которой нужно импортировать стиль</param>
 470:          /// <param name="sourceStyleName">Имя импортируемого стиля</param>  
 471:          /// <param name="resultStyleName">Имя результирующего стиля</param> 
 472:          /// <returns>Возвращается ссылка на добавленный в базу данных чертежа стиль.
 473:          /// Если импорт не удался - возвращается null</returns>
 474:          public TextStyleTableRecord ImportFromDb(Database database, string sourceStyleName,
 475:              string resultStyleName)
 476:          {
 477:              if (Exists(resultStyleName)) throw new System.Exception(
 478:      string.Format(TextStyleMngRes.StyleAlredyExists, resultStyleName));
 479:   
 480:              if (database == null)
 481:                  throw new System.Exception(TextStyleMngRes.NullNotAllowed);
 482:   
 483:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 484:              {
 485:                  TextStyleTable xTs = (TextStyleTable)t.GetObject(database.TextStyleTableId,
 486:                      OpenMode.ForRead, false, false);
 487:                  if (!xTs.Has(sourceStyleName))
 488:                      throw new System.Exception(
 489:                          string.Format(TextStyleMngRes.DbNotHasStyle, sourceStyleName));
 490:   
 491:                  ObjectIdCollection c = new ObjectIdCollection() { (ObjectId)xTs[sourceStyleName] };
 492:                  TextStyleTable cTst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 493:                      OpenMode.ForWrite);
 494:                  IdMapping idMap = new IdMapping();
 495:                  TargetDb.WblockCloneObjects(c, cTst.ObjectId, idMap, DuplicateRecordCloning.Replace,
 496:                      false);
 497:                  t.Commit();
 498:              }
 499:   
 500:              return GetStyle(resultStyleName);
 501:          }
 502:          /// <summary>
 503:          /// Импорт стиля из другого чертежа
 504:          /// </summary>
 505:          /// <param name="drawingName">Имя файла чертежа, из которой нужно импортировать стиль</param>
 506:          /// <param name="password">Пароль к файлу чертежа. Если пароля нет - следует 
 507:          /// передавать пустую строку</param>
 508:          /// <param name="sourceStyleName">Имя импортируемого стиля</param>  
 509:          /// <param name="resultStyleName">Имя результирующего стиля</param> 
 510:          /// <returns>Возвращается ссылка на добавленный в базу данных чертежа стиль.
 511:          /// Если импорт не удался - возвращается null</returns>
 512:          public TextStyleTableRecord ImportFromDrawing(string drawingName, string password,
 513:              string sourceStyleName, string resultStyleName)
 514:          {
 515:              if (Exists(resultStyleName)) throw new System.Exception(string.Format(
 516:                  TextStyleMngRes.StyleAlredyExists, resultStyleName));
 517:   
 518:              FileInfo file = new FileInfo(drawingName);
 519:              if (!file.Exists) throw new System.Exception(string.Format(TextStyleMngRes.FileNotFound,
 520:                  drawingName));
 521:   
 522:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 523:              {
 524:                  using (Database xDb = new Database(false, false))
 525:                  {
 526:                      xDb.ReadDwgFile(drawingName, FileShare.Read, true, password);
 527:                      TextStyleTable xTs = (TextStyleTable)t.GetObject(xDb.TextStyleTableId,
 528:                          OpenMode.ForRead,
 529:                          false, false);
 530:                      if (!xTs.Has(sourceStyleName)) throw new System.Exception(string.Format(
 531:                          TextStyleMngRes.FileNotHasStyle, drawingName, sourceStyleName));
 532:                      ObjectIdCollection c = new ObjectIdCollection() { (ObjectId)xTs[sourceStyleName] };
 533:   
 534:                      TextStyleTable cTst = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 535:                          OpenMode.ForWrite);
 536:                      IdMapping idMap = new IdMapping();
 537:                      TargetDb.WblockCloneObjects(c, cTst.ObjectId, idMap, DuplicateRecordCloning.Replace,
 538:                          false);
 539:                      t.Commit();
 540:                  }
 541:              }
 542:              return GetStyle(resultStyleName);
 543:          }
 544:          /// <summary>
 545:          /// Объединение двух стилей в один. Стиль, имя которого передано в качестве первого параметра
 546:          /// будет удалён и останется только стиль, имя которого передано в качестве второго параметра. Все
 547:          /// объекты, использовавшие первый стиль, станут использовать второй стиль.
 548:          /// </summary>
 549:          /// <param name="unitedStyleName">Имя стиля, который должен исчезнуть после объединения</param>
 550:          /// <param name="resultStyleName">Имя результирующего стиля</param>
 551:          /// <returns>Возвращает ObjectId результирующего стиля. В случае неудачи возвращается 
 552:          /// ObjectId.Null
 553:          /// </returns>
 554:          public ObjectId Union(string unitedStyleName, string resultStyleName)
 555:          {
 556:              return Union(new string[] { unitedStyleName }, resultStyleName);
 557:          }
 558:          /// <summary>
 559:          /// Объединение сразу нескольких стилей в один. Стили, имена которых указаны в переданном  
 560:          /// параметре метода будут удалены - останется только стиль, имя которого указано 
 561:          /// вторым параметром. Все объекты, использовавшие удаляемые стили станут использовать целевой 
 562:          /// стиль.
 563:          /// </summary>
 564:          /// <param name="unitedStyleNames">Имена стилей, которые должны исчезнуть после объединения
 565:          /// </param>
 566:          /// <param name="resultStyleName">Имя результирующего стиля</param>
 567:          /// <returns>Возвращает ObjectId результирующего стиля. В случае неудачи возвращается 
 568:          /// ObjectId.Null
 569:          /// </returns>
 570:          public ObjectId Union(string[] unitedStyleNames, string resultStyleName)
 571:          {
 572:              //Из тех имён стилей, которые указаны как удаляемые после объединения, выберем те, которые
 573:              //действительно содержатся в базе данных чертежа
 574:              unitedStyleNames = unitedStyleNames.Where(n => Exists(n)).Select(n => n.Trim()
 575:                  .ToUpper()).ToArray();
 576:   
 577:              //Если искомых стилей не найдено - возвращаем ObjectId.Null
 578:              if (unitedStyleNames.Length == 0)
 579:                  return ObjectId.Null;
 580:   
 581:              //Если не найден результирующий стиль (тот, который должен остаться после объединения) -
 582:              //возвращаем ObjectId.Null
 583:              if (!Exists(resultStyleName))
 584:                  return ObjectId.Null;
 585:   
 586:              //Получаем идентификаторы примитивов, использующих стили, 
 587:              //которые должны исчезнуть после объединения
 588:              Dictionary<string, ObjectId[]> dict = GetDependentPrimitives(unitedStyleNames);
 589:   
 590:              //Получаем идентификатор того стиля, который нужно назначить используемым для примитивов,
 591:              //идентификаторы которых содержатся в переменной ids
 592:              ObjectId resultId = GetStyle(resultStyleName).ObjectId;
 593:   
 594:              //Если текущим текстовым стилем является один из удаляемых, то назначаем текущим
 595:              //результирующий текстовый стиль
 596:              if (unitedStyleNames.Select(n => n.Trim().ToUpper()).Contains(GetStyle(TargetDb.Textstyle)
 597:                  .Name.Trim().ToUpper()))
 598:                  TargetDb.Textstyle = resultId;
 599:   
 600:              //Создаём транзакцию, в рамках которой каждому примитиву из массива ids назначаем
 601:              //используемым текстовым стилем тот, который должен остаться после объединения стилей
 602:              using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 603:              {
 604:                  foreach (var _style in dict)
 605:                  {
 606:                      //Атрибуты, входящие в состав определения блоков должны быть обновлены до того, 
 607:                      //как будут анализироваться примитивы вхождений блоков
 608:   
 609:                      //Выбираю все определения атрибутов
 610:                      AttributeDefinition[] attdefs = _style.Value.Where(n => t.GetObject(n,
 611:                          OpenMode.ForRead) is AttributeDefinition).Select(n =>
 612:                              (AttributeDefinition)t.GetObject(n, OpenMode.ForWrite)).ToArray();
 613:   
 614:                      //Обновляю текстовые стили, назначенные атрибутам в определениях блоков
 615:                      foreach (AttributeDefinition attdef in attdefs)
 616:                      {
 617:                          attdef.TextStyle = resultId;
 618:                          attdef.UpdateMTextAttributeDefinition();
 619:                      }
 620:   
 621:                      foreach (var _x in _style.Value)
 622:                      {
 623:                          DBObject item = t.GetObject(_x, OpenMode.ForWrite);
 624:   
 625:                          //Если это размерный стиль
 626:                          if (item is DimStyleTableRecord)
 627:                          {
 628:                              DimStyleTableRecord dstr = (DimStyleTableRecord)item;
 629:                              dstr.Dimtxsty = resultId;
 630:                          }
 631:                          //Если это стиль мультивыноски
 632:                          else if (item is MLeaderStyle)
 633:                          {
 634:                              MLeaderStyle mls = (MLeaderStyle)item;
 635:                              mls.TextStyleId = resultId;
 636:                          }
 637:                          //Если это табличный стиль
 638:                          else if (item is TableStyle)
 639:                          {
 640:                              TableStyle ts = (TableStyle)item;
 641:                              //В цикле проверяем текстовый стиль каждой ячейки таблицы
 642:                              foreach (string cellStyle in ts.CellStyles)
 643:                              {
 644:                                  if (unitedStyleNames.Contains(GetStyle(ts.TextStyle(cellStyle))
 645:                                      .Name.Trim().ToUpper()))
 646:                                      ts.SetTextStyle(resultId, cellStyle);
 647:                              }
 648:                          }
 649:                          //Если это однострочный текст, не являющийся при этом атрибутом 
 650:                          //определения блока
 651:                          else if ((item is DBText) && !(item is AttributeDefinition))
 652:                          {
 653:                              DBText txt = (DBText)item;
 654:                              txt.TextStyle = resultId;
 655:   
 656:                              if (txt is AttributeReference)
 657:                                  ((AttributeReference)txt).UpdateMTextAttribute();
 658:                          }
 659:                          //Если это многострочный текст
 660:                          else if (item is MText)
 661:                          {
 662:                              MText txt = (MText)item;
 663:                              txt.TextStyle = resultId;
 664:                          }
 665:                          //Если это примитив, реализующий интерфейс IAcadText
 666:                          else if (item is IAcadText)
 667:                          {
 668:                              IAcadText txt = (IAcadText)item;
 669:                              txt.StyleName = resultStyleName;
 670:                          }
 671:                          //Если это примитив, реализующий интерфейс IAcadMText
 672:                          else if (item is IAcadMText)
 673:                          {
 674:                              IAcadMText txt = (IAcadMText)item;
 675:                              txt.StyleName = resultStyleName;
 676:                          }
 677:                          //Если это таблица
 678:                          else if (item is Table)
 679:                          {
 680:                              Table table = (Table)item;
 681:                              string[] styleNames = unitedStyleNames;
 682:                              //Сначала проверяю, какие стили текста назначены столбцам
 683:                              for (int i = 0; i < table.NumColumns; i++)
 684:                                  if (styleNames.Contains(table.GetCellStyle(-1, i).ToUpper().Trim()))
 685:                                  {
 686:                                      table.SetCellStyle(-1, i, resultStyleName);
 687:                                  }
 688:                              //Теперь проверяю, какие стили текста назначены строкам
 689:                              for (int i = 0; i < table.NumRows; i++)
 690:                                  if (styleNames.Contains(table.GetCellStyle(i, -1).ToUpper().Trim()))
 691:                                  {
 692:                                      table.SetCellStyle(i, -1, resultStyleName);
 693:                                  }
 694:                              //Анализируем каждую ячейку таблицы
 695:                              //Цикл по столбцам
 696:                              for (int i = 0; i < table.NumColumns; i++)
 697:                              {
 698:                                  //Цикл по строкам
 699:                                  for (int k = 0; k < table.NumRows; k++)
 700:                                  {
 701:                                      //Анализируем конкретную ячейку таблицы
 702:                                      if (styleNames.Contains(table.GetCellStyle(k, i).ToUpper().Trim()))
 703:                                      {
 704:                                          table.SetCellStyle(k, i, resultStyleName);
 705:                                      }
 706:                                  }
 707:                              }
 708:                          }
 709:                      }
 710:                  }
 711:                  //Организовываю цикл, в котором проверяю, может ли быть удалён
 712:                  //текстовый стиль. Если может - удаляю его.
 713:                  foreach (string item in unitedStyleNames)
 714:                      if (CanBeRemoved(item))
 715:                      {
 716:                          TextStyleTableRecord tsr =
 717:                              (TextStyleTableRecord)t.GetObject(GetStyle(item).ObjectId, OpenMode.ForWrite);
 718:                          tsr.Erase();
 719:                      }
 720:                  //Сохраняю изменения, выполненные в рамках транзакции
 721:                  t.Commit();
 722:              }
 723:              //Возвращаю идентификатор результирующего текстового стиля
 724:              return resultId;
 725:          }
 726:          /// <summary>
 727:          /// Проверка на то, может ли указанный стиль быть удалён из базы данных чертежа.
 728:          /// Если стиль не имеет имени 'Standard' и при этом не может быть удалён, значит он используется
 729:          /// какими-то примитивами.
 730:          /// </summary>
 731:          /// <param name="styleName">Имя стиля, который нужно проверить на предмет возможности его 
 732:          /// удаления из чертежа</param>
 733:          /// <returns>True - стиль может быть удалён; False - не может быть удалён.</returns>
 734:          public bool CanBeRemoved(string styleName)
 735:          {
 736:              ObjectIdCollection c = new ObjectIdCollection(new ObjectId[] { 
 737:                  GetStyle(styleName).ObjectId });
 738:              TargetDb.Purge(c);
 739:              return c.Count != 0;
 740:          }
 741:          /// <summary>
 742:          /// Удалить стиль
 743:          /// </summary>
 744:          /// <param name="styleName">Имя стиля, который нужно удалить</param>
 745:          public void Remove(string styleName)
 746:          {
 747:              //Проверяем, не используется ли этот текстовый стиль примитивами
 748:              if (CanBeRemoved(styleName))
 749:              {
 750:                  using (Transaction t = TargetDb.TransactionManager.StartTransaction())
 751:                  {
 752:                      TextStyleTable table = (TextStyleTable)t.GetObject(TargetDb.TextStyleTableId,
 753:                          OpenMode.ForWrite);
 754:                      TextStyleTableRecord style = (TextStyleTableRecord)t.GetObject(table[styleName],
 755:                          OpenMode.ForWrite);
 756:                      style.Erase();
 757:                      t.Commit();
 758:                  }
 759:              }
 760:          }
 761:      }
 762:  }

    Номера строк 213 и 224 я подсветил красным цветом - это проблемные места, решением которых я занимаюсь на данный момент (см. ниже TODO п.1). Пока что давайте напишем примеры, в которых будет продемонстрировано, как следует использовать наш менеджер текстовых стилей.

TODO:

  1. В случае работы метода Union (пример txtTest_6) объединение стилей происходит не всегда (если его используют только объекты однострочного и многострочного текста - тут проблем нет)... Например я назначил табличному, размерному и мультивыносок стилям тот текстовый стиль, который должен исчезнуть после объединения. Затем создал примитивы, использующие эти стили. Так же создал определение блока, в котором имелся текст, использующий обозначенный стиль текста и атрибут. В идеале после объединения все стили и примитивы должны переориентироваться на др. тестовый стиль (в т.ч. и в составе определения блока). Однако это произошло не везде: атрубут блока и ячейка таблицы, в которой стиль текста изначально принудительно был назначен иным - не изменили стиль текста на нужный. В исходном коде метода ObjectId Union(string[] unitedStyleNames, string resultStyleName) я ставил точку остановки (брэйкпоинт) в строке 616 кода (см. код, приведённый выше), однако по факту остановки не произошло. Т.е. я делаю вывод, что определения атрибутов почему-то не попали в мою выборку, хотя я отлавливаю DBText (AttributeDefinition наследуется от него). Т.о. На предмет объединения текстовых стилей я буду ещё производить тесты и править код, пока не достигну окончательного нужного результата [примечание: обновление текстовых стилей для атрибутов блоков и для их вхождений сделал - чуть позже обновлю код исходников, сейчас разбираюсь с таблицами...].
  2. В процессе работы примера txtTest_7, если расскомментировать строку 56 возникает исключение при попытке назначения активным документом только что открытый. Назначение я произвожу в соответствии с примером из официальной документации, однако в этом случае возникне ошибка (в коде примера "Импорт текстовых стилей из другого чертежа" см. строку кода 56 - номер строки подсвечен красным цветом).
  3. В результате работы примера txtTest_9 текстовый стиль создаётся в другом, не открытом файле чертежа (как мы этого и хотим), однако на той виртуальной машине, которую я использую в офисе по завершению работы команды появляется окошко с сообщением: 
    Warning: An error occured during save.
    We recommend that you run RECOVER on the drawing.
    Если открыть файл, в который мы добавляли новый текстовый стиль, то увидим, что стиль добавлен. Команда Audit не выявляет в чертеже никаких ошибок. Однако на домашней виртуальной машине такого сообщения у меня не появляется - всё отрабатывает гладко... Причина появления выше обозначенного сообщения мне пока не ясна (разбираюсь).