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

29/10/2016

Разделение ячеек спецификации

Евгений Пашин задал на форуме интересный вопрос. В пользовательском интерфейсе есть возможность объединения и разделения ячеек спецификации. С помощью Revit API объединить ячейки достаточно просто. Нужно попользоваться методом TableSectionData.MergeCells. А как снять объединение с помощью Revit API?

Покопавшись в файле справки по Revit API, метода типа Unmerge я не обнаружил. Одним из предположений было, что для разделения ячеек необходимо также использовать метод TableSectionData.MergeCells, но задав какие-то специфические параметры. Тем более, что в интерфейсе это тоже одна кнопка:

 

Но, метод MergeCells принимает в качестве параметров только один аргумент – TableMergedCell, в котором задаются номера верхней левой ячейки и нижней правой. Не похоже на то, что можно его как-то применить.

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

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

Код - C#: [Выделить]
  1. var header = viewSchedule.GetTableData().GetSectionData(SectionType.Header);
  2.                                                                
  3. // получаем количество строк и столбцов в секции
  4. var cNumber = header.NumberOfColumns;
  5. var rNumber = header.NumberOfRows;
  6.  
  7. // Пробегаемся по всем строкам
  8. for (int r = 0; r < rNumber; r++)
  9. {
  10.                 // индекс новой последней строки
  11.                 var newRowNumber = rNumber+r;
  12.                
  13.                 // вставляем новую стоку в конец секции
  14.                 header.InsertRow(newRowNumber);
  15.                
  16.                 // и по столбцам строки
  17.                 for (int c = 0; c < cNumber; c++)
  18.                 {
  19.                                // берем тип исходной ячейки
  20.                                var cellType = header.GetCellType(r,c);
  21.                                                                                                              
  22.                                // устанавливаем для новой ячейки такой же тип
  23.                                header.SetCellType(newRowNumber, c, cellType);
  24.                               
  25.                                // далее, в зависимости от типа ячейки разными методами копируем значение из исходной ячейки в новую
  26.                                switch (cellType)
  27.                                {
  28.                                                case CellType.Text:
  29.                                                                header.SetCellText(newRowNumber, c, header.GetCellText(r,c));
  30.                                                                break;
  31.                                                case CellType.CalculatedValue:
  32.                                                                header.SetCellCalculatedValue(newRowNumber, c, header.GetCellCalculatedValue(r,c));
  33.                                                                break;
  34.                                                case CellType.CombinedParameter:
  35.                                                                header.SetCellCombinedParameters(newRowNumber, c, header.GetCellCombinedParameters(r,c));
  36.                                                                break;
  37.                                                case CellType.Graphic:
  38.                                                                // скопировать изображение так и не полчилось.
  39.                                                                //header.InsertImage(newRowNumber, c, header.GetCellParamId(r,c));
  40.                                                                break;
  41.                                                case CellType.Parameter:
  42.                                                                header.SetCellParamIdAndCategoryId(newRowNumber, c, header.GetCellParamId(r,c), header.GetCellCategoryId(r,c));
  43.                                                                break;
  44.                                                case CellType.ParameterText:
  45.                                                                header.SetCellText(newRowNumber, c, header.GetCellText(r,c));
  46.                                                                break;                                                                                                
  47.                                }
  48.                 }
  49.                                                                                              
  50. }
  51.  
  52. // удаляем исходные строки
  53. for (int r = rNumber-1; r >= 0; r--)
  54. {
  55.                 header.RemoveRow(r);
  56. }

Данный код в целом работает на простых спецификациях. Проблема с копированием изображения в спецификации. Метода, который вернул бы идентификатор изображения в ячейки я не нашел. Возможно его можно получить неявным образом.

Однако, дорабатывать данный код я так и не стал, так как появилось предложение от пользователя Drakus. Он сообщил, что реализовывал разделение ячеек с помощью метода SetMergedCell, путем перебора всех объединенных ячеек и задания для них диапазона, равного 1 ячейке.

У Евгения так и не получилось использовать этот метод. У меня, кстати тоже.

Метод SetMergedCell позволяет к существующему объединению добавить еще ячейку. При этом одиночная ячейка рассматривается тоже как объединения, но объединение состоит из одной ячейки. Т.е. границы объединения – та же самая ячейка.

Сначала я предположил, что если взять одну ячейку из объединения, и установить объединение для нее самой же, то Revit их разъединит.

Тестировал я на вот таком примере:

 

Т.е. если выполнить вот такой код:

tableSectionData.SetMergedCell(0,0, new TableMergedCell(0,0,0,0));
, то я ожидал, что ячейки в самой верхней строке будут разделены. Но нет, чуда не произошло.

Дальнейшим шагом был перебор всех ячеек секции спецификации с выполнением метода SetMergedCell:

Код - C#: [Выделить]
  1. for (int r = 0; r < tableSectionData.LastRowNumber; r++)
  2. {                                                                                                                                                                                                          
  3.                 for (int c = 0; c < tableSectionData.LastColumnNumber; c++)
  4.                 {                                                                                                                                           
  5.                                tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
  6.                               
  7.                 }
  8. }

И наконец-то удача. После выполнения увидел все разъединенные ячейки:

 

Но данный метод разделяет все ячейки. Как мы видим, значения, которые были в ячейках до объединения, сохранились. Изображение в ячейке – тоже.

Что если нужно разъединить одну объединенную ячейку? Очень просто. У объединенной ячейки есть номера левой верхней и правой нижней ячейки. Соответственно, нужно пробежаться не по всем ячейкам, а только по ячейкам из заданного диапазона:

Код - C#: [Выделить]
  1. for (int r = mergedCell.Top; r <= mergedCell.Bottom; r++)
  2. {
  3.                 for (int c = mergedCell.Left; c <= mergedCell.Right; c++)
  4.                 {
  5.                                tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
  6.                 }
  7. }

Финальный шаг. Так как для класса TableSectionData так и напрашивался метод UmergeCells, реализуем его с помощью методов расширения. Получился вот такой вот вспомогательный класс, содержащий 3 метода.

Код - C#: [Выделить]
  1. static class TableSectionDataHelper
  2. {
  3.                 /// <summary>
  4.                 /// Разделение объединенной ячейки. Необходимо передать номера строки
  5.                 /// и столбца любой ячейки, входящей в объединенную ячйку
  6.                 /// </summary>
  7.                 /// <param name="tableSectionData">Секция спецфикации</param>
  8.                 /// <param name="rNum">Номер строки</param>
  9.                 /// <param name="cNum">Номер столбца</param>
  10.                 public static void UnmergeCell(this TableSectionData tableSectionData, int rNum, int cNum)
  11.                 {
  12.                                // получаем объединенную ячейку, которая содержит одиносную ячейку
  13.                                var mergedCell = tableSectionData.GetMergedCell(rNum,cNum);
  14.                               
  15.                                UnmergeCell(tableSectionData, mergedCell);
  16.                 }
  17.                
  18.                 /// <summary>
  19.                 /// Разделение объединенной ячейки.
  20.                 /// </summary>
  21.                 /// <param name="tableSectionData">Секция спецификации</param>
  22.                 /// <param name="mergedCell">Объединенная ячейка</param>
  23.                 public static void UnmergeCell(this TableSectionData tableSectionData, TableMergedCell mergedCell)
  24.                 {
  25.                                for (int r = mergedCell.Top; r <= mergedCell.Bottom; r++)
  26.                                {
  27.                                                for (int c = mergedCell.Left; c <= mergedCell.Right; c++)
  28.                                                {
  29.                                                                tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
  30.                                                }
  31.                                }
  32.                 }
  33.                               
  34.                 /// <summary>
  35.                 /// Разделение всех ячеек секции спецификации
  36.                 /// </summary>
  37.                 /// <param name="tableSectionData">Секция спецификации</param>
  38.                 public static void UnmergeAllCells(this TableSectionData tableSectionData)
  39.                 {
  40.                                for (int r = 0; r < tableSectionData.LastRowNumber; r++)
  41.                                {                                                                                                                                                                                                          
  42.                                                for (int c = 0; c < tableSectionData.LastColumnNumber; c++)
  43.                                                {                                                                                                                                           
  44.                                                                tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
  45.                                                               
  46.                                                }
  47.                                }
  48.                 }
  49. }

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

Код - C#: [Выделить]
  1. var header = viewSchedule.GetTableData().GetSectionData(SectionType.Header);
  2. header.UnmergeCell(2,1);

Результат:

 


Спасибо Евгению за вопрос и Drakus за полезную подсказку.

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

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

Опубликовано 29.10.2016
Отредактировано 30.10.2016 в 00:54:30