Разделение ячеек спецификации
Евгений Пашин задал на форуме интересный вопрос. В пользовательском интерфейсе есть возможность объединения и разделения ячеек спецификации. С помощью Revit API объединить ячейки достаточно просто. Нужно попользоваться методом TableSectionData.MergeCells. А как снять объединение с помощью Revit API?
Покопавшись в файле справки по Revit API, метода типа Unmerge я не обнаружил. Одним из предположений было, что для разделения ячеек необходимо также использовать метод TableSectionData.MergeCells, но задав какие-то специфические параметры. Тем более, что в интерфейсе это тоже одна кнопка:
Но, метод MergeCells принимает в качестве параметров только один аргумент – TableMergedCell, в котором задаются номера верхней левой ячейки и нижней правой. Не похоже на то, что можно его как-то применить.
Следующей идей было копирование ячеек в новые и удаление старых. Несмотря на то, что ячейки визуально объединены, Revit все равно позволяет обращаться к одиночной ячейки внутри объединения и даже получить ее значение.
В результате тестирования у меня получился следующий код, который позволяет разделить все ячейки секции спецификации:
- var header = viewSchedule.GetTableData().GetSectionData(SectionType.Header);
- // получаем количество строк и столбцов в секции
- var cNumber = header.NumberOfColumns;
- var rNumber = header.NumberOfRows;
- // Пробегаемся по всем строкам
- for (int r = 0; r < rNumber; r++)
- {
- // индекс новой последней строки
- var newRowNumber = rNumber+r;
- // вставляем новую стоку в конец секции
- header.InsertRow(newRowNumber);
- // и по столбцам строки
- for (int c = 0; c < cNumber; c++)
- {
- // берем тип исходной ячейки
- var cellType = header.GetCellType(r,c);
- // устанавливаем для новой ячейки такой же тип
- header.SetCellType(newRowNumber, c, cellType);
- // далее, в зависимости от типа ячейки разными методами копируем значение из исходной ячейки в новую
- switch (cellType)
- {
- case CellType.Text:
- header.SetCellText(newRowNumber, c, header.GetCellText(r,c));
- break;
- case CellType.CalculatedValue:
- header.SetCellCalculatedValue(newRowNumber, c, header.GetCellCalculatedValue(r,c));
- break;
- case CellType.CombinedParameter:
- header.SetCellCombinedParameters(newRowNumber, c, header.GetCellCombinedParameters(r,c));
- break;
- case CellType.Graphic:
- // скопировать изображение так и не полчилось.
- //header.InsertImage(newRowNumber, c, header.GetCellParamId(r,c));
- break;
- case CellType.Parameter:
- header.SetCellParamIdAndCategoryId(newRowNumber, c, header.GetCellParamId(r,c), header.GetCellCategoryId(r,c));
- break;
- case CellType.ParameterText:
- header.SetCellText(newRowNumber, c, header.GetCellText(r,c));
- break;
- }
- }
- }
- // удаляем исходные строки
- for (int r = rNumber-1; r >= 0; r--)
- {
- header.RemoveRow(r);
- }
Данный код в целом работает на простых спецификациях. Проблема с копированием изображения в спецификации. Метода, который вернул бы идентификатор изображения в ячейки я не нашел. Возможно его можно получить неявным образом.
Однако, дорабатывать данный код я так и не стал, так как появилось предложение от пользователя Drakus. Он сообщил, что реализовывал разделение ячеек с помощью метода SetMergedCell, путем перебора всех объединенных ячеек и задания для них диапазона, равного 1 ячейке.
У Евгения так и не получилось использовать этот метод. У меня, кстати тоже.
Метод SetMergedCell позволяет к существующему объединению добавить еще ячейку. При этом одиночная ячейка рассматривается тоже как объединения, но объединение состоит из одной ячейки. Т.е. границы объединения – та же самая ячейка.
Сначала я предположил, что если взять одну ячейку из объединения, и установить объединение для нее самой же, то Revit их разъединит.
Тестировал я на вот таком примере:
Т.е. если выполнить вот такой код:
Дальнейшим шагом был перебор всех ячеек секции спецификации с выполнением метода SetMergedCell:
- for (int r = 0; r < tableSectionData.LastRowNumber; r++)
- {
- for (int c = 0; c < tableSectionData.LastColumnNumber; c++)
- {
- tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
- }
- }
И наконец-то удача. После выполнения увидел все разъединенные ячейки:
Но данный метод разделяет все ячейки. Как мы видим, значения, которые были в ячейках до объединения, сохранились. Изображение в ячейке – тоже.
Что если нужно разъединить одну объединенную ячейку? Очень просто. У объединенной ячейки есть номера левой верхней и правой нижней ячейки. Соответственно, нужно пробежаться не по всем ячейкам, а только по ячейкам из заданного диапазона:
- for (int r = mergedCell.Top; r <= mergedCell.Bottom; r++)
- {
- for (int c = mergedCell.Left; c <= mergedCell.Right; c++)
- {
- tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
- }
- }
Финальный шаг. Так как для класса TableSectionData так и напрашивался метод UmergeCells, реализуем его с помощью методов расширения. Получился вот такой вот вспомогательный класс, содержащий 3 метода.
- static class TableSectionDataHelper
- {
- /// <summary>
- /// Разделение объединенной ячейки. Необходимо передать номера строки
- /// и столбца любой ячейки, входящей в объединенную ячйку
- /// </summary>
- /// <param name="tableSectionData">Секция спецфикации</param>
- /// <param name="rNum">Номер строки</param>
- /// <param name="cNum">Номер столбца</param>
- public static void UnmergeCell(this TableSectionData tableSectionData, int rNum, int cNum)
- {
- // получаем объединенную ячейку, которая содержит одиносную ячейку
- var mergedCell = tableSectionData.GetMergedCell(rNum,cNum);
- UnmergeCell(tableSectionData, mergedCell);
- }
- /// <summary>
- /// Разделение объединенной ячейки.
- /// </summary>
- /// <param name="tableSectionData">Секция спецификации</param>
- /// <param name="mergedCell">Объединенная ячейка</param>
- public static void UnmergeCell(this TableSectionData tableSectionData, TableMergedCell mergedCell)
- {
- for (int r = mergedCell.Top; r <= mergedCell.Bottom; r++)
- {
- for (int c = mergedCell.Left; c <= mergedCell.Right; c++)
- {
- tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
- }
- }
- }
- /// <summary>
- /// Разделение всех ячеек секции спецификации
- /// </summary>
- /// <param name="tableSectionData">Секция спецификации</param>
- public static void UnmergeAllCells(this TableSectionData tableSectionData)
- {
- for (int r = 0; r < tableSectionData.LastRowNumber; r++)
- {
- for (int c = 0; c < tableSectionData.LastColumnNumber; c++)
- {
- tableSectionData.SetMergedCell(r,c, new TableMergedCell(r,c,r,c));
- }
- }
- }
- }
Использование очень простое. Например, если нам нужно разделить ячейку с изображением, то достаточно написать следующее:
- var header = viewSchedule.GetTableData().GetSectionData(SectionType.Header);
- header.UnmergeCell(2,1);
Результат:
Спасибо Евгению за вопрос и Drakus за полезную подсказку.
Обсуждение: http://adn-cis.org/forum/index.php?topic=7416
Опубликовано 29.10.2016Отредактировано 30.10.2016 в 00:54:30