При программном формировании печатных форм и отчетов в формате Microsoft Word через механизм COM-соединения часто возникает необходимость динамически удалять лишние строки в таблицах. Однако стандартный вызов метода Таблица.Rows(НомерСтроки).Delete() может завершиться критической ошибкой, если в таблице присутствуют объединенные по вертикали ячейки.
Проанализируем ситуацию, выясним внутренние причины такого поведения объектной модели Word и разберем проверенные способы решения этой задачи из кода 1С.
При попытке удаления строки обычным способом:
Таблица = ДокументВорд.Tables(1);
Таблица.Rows(2).Delete();
Платформа 1С возвращает исключение:
«Произошла исключительная ситуация (Microsoft Word): Отсутствует доступ к отдельным строкам, поскольку таблица имеет ячейки, объединенные по вертикали.»
Особенность объектной модели Microsoft Word заключается в свойстве Uniform (однородность сетки таблицы). Если в таблице есть хотя бы одно вертикальное объединение ячеек (даже если оно находится в самом конце документа), свойство Таблица.Uniform принимает значение False. При этом Word полностью блокирует доступ к коллекциям Rows и Columns по индексам для всей таблицы целиком. Из-за этого прямое обращение к даже абсолютно «простой» строке без объединений становится невозможным.
Разберем основные варианты обхода этого ограничения.
Так как коллекция Rows недоступна, мы можем обратиться к конкретным ячейкам строки через метод Cell(НомерСтроки, НомерКолонки), получить границы диапазона от первой до последней ячейки удаляемой строки и выполнить удаление ячеек.
Посмотрим на пример кода:
// Определяем номер удаляемой строки и общее количество колонок
НомерСтроки = 2;
ВсегоКолонок = 8;
// Получаем начало первой ячейки и конец последней ячейки строки
ПозицияНачала = Таблица.Cell(НомерСтроки, 1).Range.Start;
ПозицияКонца = Таблица.Cell(НомерСтроки, ВсегоКолонок).Range.End;
// Формируем общий диапазон строки через объект документа и удаляем ячейки
ДиапазонСтроки = ДокументВорд.Range(ПозицияНачала, ПозицияКонца);
ДиапазонСтроки.Cells.Delete();
Важное замечание: при вызове метода Cells.Delete() без параметров Word по умолчанию может применить сдвиг влево или вверх. Чтобы гарантированно удалить именно всю строку таблицы, рекомендуется явно передавать системную константу Word wdDeleteCellsEntireRow = 3:
// 3 — числовой эквивалент константы wdDeleteCellsEntireRow
ДиапазонСтроки.Cells.Delete(3);
Еще один лаконичный способ — взять диапазон одной ячейки из удаляемой строки и программно расширить его до границ всей строки с помощью метода Expand. Для этого используется константа wdRow = 10.
Рассмотрим реализацию данного метода:
НомерСтроки = 2;
// Получаем диапазон первой ячейки строки
ДиапазонЯчейки = Таблица.Cell(НомерСтроки, 1).Range;
// Расширяем диапазон до всей строки (wdRow = 10)
ДиапазонЯчейки.Expand(10);
// Удаляем строку через полученный диапазон
ДиапазонЯчейки.Rows.Delete();
В отличие от обращения к коллекции Таблица.Rows, метод Rows.Delete() у локально выделенного диапазона Range отрабатывает без исключений.
Контекст выделения объекта Selection в Microsoft Word также не блокируется свойством Uniform. Мы можем установить курсор в удаляемую строку и вызвать удаление через выделенную область.
Разберем по шагам:
НомерСтроки = 2;
// Выделяем ячейку
Таблица.Cell(НомерСтроки, 1).Select();
// Удаляем строку через объект Selection приложения Word
ВордПриложение.Selection.Rows.Delete();
Этот способ надежен, но требует наличия активного объекта Word.Application и может работать медленнее при пакетной обработке больших документов из-за переключения фокуса.
Чтобы избежать подобных ошибок при автоматизации формирования документов из 1С, придерживайтесь следующих правил:
Cell.Merge). Вертикальное объединение должно быть самым последним шагом оформления таблицы.