В процессе разработки прикладных решений на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью динамического управления интерфейсом. Одной из типичных задач является скрытие пустых или неиспользуемых колонок в табличных частях документов или справочников. На первый взгляд задача кажется тривиальной, однако при её реализации в управляемом интерфейсе разработчики регулярно совершают ошибки, приводящие к падению системы с сообщением вида Поле объекта не обнаружено.
В рамках этой статьи мы подробно разберем, как правильно управлять видимостью колонок табличной части, проанализируем синтаксис обращения к элементам формы, оптимизируем код для повышения производительности и рассмотрим важные системные механизмы платформы, которые необходимо учитывать для стабильной работы логики программы.
Рассмотрим ситуацию, с которой часто начинают начинающие разработчики. Нам необходимо проанализировать табличную часть, сложить значения числовой колонки по всем строкам и, если итоговая сумма равна нулю, полностью скрыть эту колонку с экрана пользователя. Ниже приведен исходный код процедуры, которая вызывала критическую ошибку:
&НаКлиенте
Процедура СкроемПустыеКолонки()
Колонки = Объект.ИтоговаяТаблица.Колонки;
Отображать41Дт = 0;
Для Каждого Стр11 ИЗ Объект.ИтоговаяТаблица Цикл
Отображать41Дт = Отображать41Дт + Стр11.Дт41;
КонецЦикла;
Если Отображать41Дт = 0 Тогда
ЭтаФорма.Элементы["ИтоговаяТаблицаДт41"].Видимость = Ложь;
КонецЕсли;
КонецПроцедуры
При выполнении данной процедуры платформа выдает ошибку, указывая на строку скрытия элемента. Выясним причину такого поведения. Проблема кроется в нескольких деталях: неправильном сопоставлении имен объектов метаданных и элементов формы, а также в особенностях обращения к коллекции элементов формы.
Проанализируем структуру управляемой формы. Нам важно четко разделять два понятия:
Объект.ИтоговаяТаблица и ее реквизит Дт41.ТаблицаФормы, а колонке — элемент типа ПолеФормы.Скрыть колонку на экране можно только через управление свойствами Элемента формы. Ошибка часто возникает из-за того, что разработчик пытается обратиться к элементу формы по имени реквизита или наоборот. По умолчанию при переносе табличной части на форму платформа генерирует имена колонок по шаблону [ИмяТаблицы][ИмяРеквизита]. Соответственно, если таблица называется ИтоговаяТаблица, а реквизит — Дт41, то имя элемента формы (колонки) будет именно ИтоговаяТаблицаДт41. Это имя необходимо проверить в конфигураторе в свойствах элемента формы.
В платформе 1С обратиться к элементу формы можно двумя синтаксическими способами. Посмотрим на примеры:
// Вариант 1: Через квадратные скобки (индексатор)
ЭтаФорма.Элементы["ИтоговаяТаблицаДт41"].Видимость = Ложь;
// Вариант 2: Прямое обращение через точку
ЭтаФорма.Элементы.ИтоговаяТаблицаДт41.Видимость = Ложь;
С точки зрения логики выполнения эти варианты абсолютно эквивалентны. Однако с точки зрения поддержки кода и процесса разработки между ними есть огромная разница, которую необходимо понимать:
Элементы.ИтоговаяТаблицаДт41 является приоритетным. При переименовании элемента формы в конфигураторе стандартные инструменты платформы (поиск ссылок, глобальная замена, рефакторинг) автоматически найдут и обновят это обращение в программном коде. Вариант со строковым литералом в квадратных скобках Элементы["ИтоговаяТаблицаДт41"] при автоматическом переименовании останется неизменным, что приведет к возникновению скрытых ошибок, которые обнаружатся только во время работы пользователя.Дт41, Дт42, Дт43), мы можем обойти их в цикле, формируя строковое имя переменной.Посмотрим на пример динамического управления видимостью группы колонок:
&НаКлиенте
Процедура СкрытьГруппуКолонокДинамически()
Для Номер = 41 По 43 Цикл
ИмяКолонки = "ИтоговаяТаблицаДт" + Номер;
// Здесь квадратные скобки технически необходимы
Элементы[ИмяКолонки].Видимость = Ложь;
КонецЦикла;
КонецПроцедуры
Таким образом, если имя колонки известно заранее и не меняется динамически, всегда используйте обращение через точку.
Вернемся к алгоритму подсчета суммы по колонке. В исходном варианте автора используется цикл Для Каждого Стр11 ИЗ Объект.ИтоговаяТаблица. Выполнение циклов обхода коллекций на клиенте — это крайне неоптимальная операция. На больших табличных частях (от нескольких сотен до тысяч строк) такой обход приведет к заметному зависанию интерфейса.
Платформа 1С предоставляет мощный встроенный инструмент для работы со списками и табличными частями — метод Итог(). Этот метод реализован на уровне платформы на C++ и оптимизирован для быстрого подсчета агрегатных величин как на сервере, так и на клиенте для объектов типа ДанныеФормыКоллекция.
Разберем оптимизированный вариант процедуры:
&НаКлиенте
Процедура СкроемПустыеКолонкиОптимизировано()
// Рассчитываем сумму по колонке Дт41 встроенным методом
СуммаДт41 = Объект.ИтоговаяТаблица.Итог("Дт41");
// Управляем видимостью элемента формы на основе полученного итога
Если СуммаДт41 = 0 Тогда
Элементы.ИтоговаяТаблицаДт41.Видимость = Ложь;
Иначе
Элементы.ИтоговаяТаблицаДт41.Видимость = Истина;
КонецЕсли;
КонецПроцедуры
Этот код работает в десятки раз быстрее ручного цикла и выглядит гораздо лаконичнее, повышая общую читаемость программного модуля.
При использовании метода Итог() на клиенте для скрытых колонок разработчики часто сталкиваются с необъяснимым поведением системы: метод возвращает 0, хотя в базе данных точно есть заполненные строки с ненулевыми значениями. Выясним причину этой особенности.
В управляемом интерфейсе 1С реализован строгий механизм минимизации трафика между сервером и клиентом. Если колонка табличной части программно или интерактивно скрыта с экрана (свойство Видимость установлено в значение Ложь), платформа считает, что пользователю эти данные сейчас не нужны. Для экономии оперативной памяти клиента и сетевого трафика значения этой колонки просто **не передаются** с сервера на клиент.
Как только данные перестают передаваться, клиентский метод Итог("Дт41") начинает оперировать пустыми значениями и выдает ложный нулевой результат. Чтобы решить эту проблему, необходимо настроить реквизит формы:
Объект -> ИтоговаяТаблица -> найдите реквизит Дт41.После этой настройки платформа будет гарантированно передавать значения колонки Дт41 на сторону клиента при любых условиях видимости, обеспечивая корректный подсчет итогов.
В реальных бизнес-приложениях у пользователей могут быть разные роли и права доступа. Если у текущего пользователя нет прав на просмотр реквизита Дт41, платформа на уровне СУБД и интерфейса исключит этот реквизит. Соответственно, элемент управления ИтоговаяТаблицаДт41 просто не будет создан на форме при ее генерации.
В таком случае попытка выполнить строку кода Элементы.ИтоговаяТаблицаДт41.Видимость = Ложь; приведет к аварийному завершению работы программы с ошибкой Поле объекта не обнаружено. Чтобы предотвратить подобные ситуации, код должен быть отказоустойчивым.
Рассмотрим два варианта написания безопасного кода.
Вариант 1. Использование метода Найти() (без БСП):
&НаКлиенте
Процедура СкроемПустыеКолонкиБезопасно()
СуммаДт41 = Объект.ИтоговаяТаблица.Итог("Дт41");
Если СуммаДт41 = 0 Тогда
// Ищем элемент в коллекции формы, метод возвращает Неопределено, если элемент не найден
КолонкаФормы = Элементы.Найти("ИтоговаяТаблицаДт41");
Если КолонкаФормы <> Неопределено Тогда
КолонкаФормы.Видимость = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Вариант 2. Использование функций Библиотеки Стандартных Подсистем (БСП):
Если ваша конфигурация разработана на основе БСП, то наиболее лаконичным и правильным подходом будет использование готовых процедур общего назначения. В модуле ОбщегоНазначенияКлиентСервер существует специальная процедура для безопасного изменения свойств элементов формы:
&НаКлиенте
Процедура СкроемПустыеКолонкиБСП()
СуммаДт41 = Объект.ИтоговаяТаблица.Итог("Дт41");
Если СуммаДт41 = 0 Тогда
// Процедура сама найдет элемент и изменит свойство, не вызывая ошибок при его отсутствии
ОбщегоНазначенияКлиентСервер.УстановитьСвойствоЭлементаФормы(
Элементы,
"ИтоговаяТаблицаДт41",
"Видимость",
Ложь
);
КонецЕсли;
КонецПроцедуры
В завершение разберем ситуацию, когда нам требуется скрывать данные выборочно. Важно помнить, что программное изменение свойства Видимость элемента формы скрывает всю колонку целиком для всей таблицы. Если перед нами стоит задача скрывать значения только в определенных строках таблицы при выполнении условий (например, скрывать задолженность, если договор закрыт), то свойство Видимость нам не поможет.
Для таких задач применяется механизм Условного оформления управляемой формы. Его настройка выполняется на сервере, например, в процедуре ПриСозданииНаСервере. Посмотрим на программный пример настройки условного оформления для нашей таблицы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Очистим или добавим новое правило оформления
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Указываем, какое свойство мы хотим изменить.
// Параметр "ТолькоПросмотр" или "Текст" часто используется для имитации скрытия данных в строке.
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Отображать", Ложь);
// 2. Указываем условие, при котором оформление сработает.
// Допустим, мы хотим скрыть ячейки, где значение реквизита Дт41 равно 0
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ИтоговаяТаблица.Дт41");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = 0;
// 3. Указываем оформляемые поля (конкретная колонка на форме)
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ИтоговаяТаблицаДт41");
КонецПроцедуры
Использование условного оформления позволяет гибко управлять отображением ячеек на уровне платформы без необходимости писать тяжеловесный код пересчета и визуализации на стороне клиента.