При разработке интерфейсов на обычных формах (в рамках платформы 1С:Предприятие 8.2 или в режиме совместимости 8.3) часто возникает задача: отобразить в списке документов, справочников или в табличном поле динамические данные, которых физически нет в самом объекте или его источнике. Например, это может быть текущий статус заказа из регистра сведений, оперативный остаток товара или расчетный показатель, который постоянно меняется.
В этой статье мы подробно разберем, как правильно решить эту задачу. Мы рассмотрим процесс программного добавления колонки, проанализируем простой, но опасный способ её заполнения через событие ПриВыводеСтроки, а также изучим профессиональный и производительный метод с использованием события ПриПолученииДанных.
Если мы работаем с типовой конфигурацией, вносить изменения в структуру метаданных журнала документов или формы нежелательно, чтобы не усложнять последующие обновления. Лучший выход — добавить колонку динамически при открытии формы.
Для этого мы используем обработчик события формы ПриОткрытии. Нам нужно обратиться к коллекции колонок табличного поля и вызвать метод Добавить. Важно оставить свойство Данные пустым, так как колонка у нас виртуальная и не привязана напрямую к реквизитам базы данных.
Разберем пример кода для добавления колонки:
Процедура ПриОткрытии()
// Добавляем новую колонку в табличное поле "ДокументСписок"
НоваяКолонка = ЭлементыФормы.ДокументСписок.Колонки.Добавить("ИмяВашейКолонки", "Статус оплаты");
// Настраиваем внешний вид и ширину
НоваяКолонка.Ширина = 15;
НоваяКолонка.Доступность = Истина;
КонецПроцедуры
После выполнения этого кода на форме появится пустая колонка с заголовком "Статус оплаты". Теперь наша задача — заполнить её данными для каждой отображаемой строки.
Самый очевидный способ, который часто выбирают начинающие разработчики, — использование события табличного поля ПриВыводеСтроки. Это событие вызывается платформой в тот момент, когда конкретная строка выводится на экран монитора.
Посмотрим на пример реализации данного подхода:
Процедура ДокументСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Проверяем, что данные строки доступны
Если ДанныеСтроки <> Неопределено Тогда
// Получаем значение (например, из реквизита ссылки или несложного вычисления)
ЗначениеКолонки = "Оплачен"; // Здесь может быть ваша логика
// Устанавливаем текст в ячейку нашей новой колонки
ОформлениеСтроки.Ячейки.ИмяВашейКолонки.УстановитьТекст(ЗначениеКолонки);
КонецЕсли;
КонецПроцедуры
Почему этот способ является «миной замедленного действия»?
Дело в том, что событие ПриВыводеСтроки срабатывает чрезвычайно часто: при каждом скроллинге списка, при изменении размеров окна, при выделении строки мышью и даже при обычном перемещении курсора. Если внутри этого обработчика вы напишете обращение к базе данных через запрос или начнете получать реквизиты через точку (например, ДанныеСтроки.Ссылка.Договор.Организация), платформа будет генерировать сотни одиночных SQL-запросов к серверу базы данных. Это классическая проблема "N+1 запроса". На реальной базе данных с десятками пользователей список документов начнет сильно зависать и «тормозить» при обычной прокрутке.
Чтобы избежать проблем с производительностью, профессиональные разработчики 1С используют событие ПриПолученииДанных. Оно спроектировано для оптимизации работы с базой данных и позволяет получить информацию пакетным (пакетным) способом сразу для всей видимой части таблицы (обычно это 30–40 строк на экране).
Разберем по шагам алгоритм правильной работы с этим событием:
В (&МассивСсылок).Проанализируем пример готового кода для оптимального заполнения колонки:
Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
// 1. Создаем структуры для сбора данных
МассивСсылок = Новый Массив;
СоответствиеСтрок = Новый Соответствие;
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
Если ДанныеСтроки <> Неопределено Тогда
// Добавляем ссылку в массив для запроса
МассивСсылок.Добавить(ДанныеСтроки.Ссылка);
// Запоминаем оформление строки по ключу-ссылке
СоответствиеСтрок.Вставить(ДанныеСтроки.Ссылка, ОформлениеСтроки);
КонецЕсли;
КонецЦикла;
// Если список пуст, выполнять запрос нет смысла
Если МассивСсылок.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// 2. Делаем ОДИН запрос для получения данных по всем видимым строкам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СтатусыДокументов.Документ КАК Ссылка,
| СтатусыДокументов.Статус КАК ЗначениеСтатуса
|ИЗ
| РегистрСведений.СтатусыДокументов КАК СтатусыДокументов
|ГДЕ
| СтатусыДокументов.Документ В(&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
// 3. Быстро заполняем ячейки данными из запроса
Пока Выборка.Следующий() Цикл
ОформлениеСтроки = СоответствиеСтрок.Получить(Выборка.Ссылка);
Если ОформлениеСтроки <> Неопределено Тогда
// Устанавливаем текст в добавленную виртуальную колонку
ОформлениеСтроки.Ячейки.ИмяВашейКолонки.УстановитьТекст(Выборка.ЗначениеСтатуса);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
При таком подходе нагрузка на базу данных снижается в десятки раз, а интерфейс программы работает плавно и быстро даже на очень больших таблицах.
Разработчику необходимо помнить об одном ключевом ограничении при работе с виртуальными колонками: пользователи не смогут выполнять стандартный поиск, сортировку или отборы по этой колонке.
Поскольку данные физически не хранятся в источнике данных табличного поля (например, в динамической выборке журнала документов базы данных), СУБД ничего не знает о существовании этой колонки. Платформа 1С не сможет составить SQL-запрос для фильтрации или сортировки по этому полю. Если вашим пользователям критически важна возможность фильтрации по этим данным, вам придется пойти другим путем: добавить реальную графу в журнал документов или справочник, либо выводить информацию через полноценный внешний отчет.
Если вы планируете переводить конфигурацию на современные управляемые формы (интерфейс "Такси"), то концепция работы со списками кардинально меняется:
ДинамическийСписок.ЛЕВОЕ СОЕДИНЕНИЕ.Тем не менее, умение работать с событиями ПриПолученииДанных остается важнейшим навыком при поддержке и развитии классических конфигураций на обычных формах.