При разработке интерфейсов на обычных формах программисты часто сталкиваются с необходимостью вывести в табличную часть дополнительные данные, которые не должны сохраняться в базе данных. Это могут быть промежуточные итоги, остатки на текущую дату, курсы валют или результаты сложных вычислений, зависящие от введенных пользователем значений. Попытка просто присвоить значение ячейке через ЭлементУправления колонки обычно приводит к тому, что данные видны только в режиме редактирования, а после выхода из него — исчезают. Разберем детально, почему так происходит и как правильно реализовать вывод динамической информации.
Проанализируем механику работы табличного поля в обычных формах. Когда мы обращаемся к свойству ЭлементыФормы.ИмяТаблицы.Колонки.ИмяКолонки.ЭлементУправления.Значение, мы обращаемся к общему шаблону элемента управления для всей колонки целиком. В 1С обычных форм поле ввода (или другой элемент) не существует физически в каждой ячейке. Платформа динамически "подкладывает" один и тот же элемент управления в ту строку, которую пользователь сейчас редактирует.
Именно поэтому, как только фокус покидает ячейку, связь между общим элементом управления и конкретной строкой разрывается. Платформа пытается отрисовать содержимое ячейки на основе данных, хранящихся в источнике (реквизите табличной части). Если колонка не привязана к реквизиту — отрисовывать нечего, и мы видим пустое поле. Выясним, какие механизмы отрисовки предоставляет платформа для решения этой задачи.
Это наиболее простой в реализации способ. Рассмотрим ситуацию: нам нужно вывести в колонку Итог произведение Цены и Количества, при этом сама колонка Итог не является реквизитом. Событие ПриВыводеСтроки срабатывает каждый раз, когда строка отрисовывается на экране (например, при прокрутке или обновлении формы).
Разберем пример кода для этого обработчика:
Процедура ТабличнаяЧастьПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Рассчитываем значение на лету
РезультатРасчета = ДанныеСтроки.Цена * ДанныеСтроки.Количество;
// Устанавливаем текст в ячейку расчетной колонки
ОформлениеСтроки.Ячейки.Итог.УстановитьТекст(Формат(РезультатРасчета, "ЧЦ=15; ЧДЦ=2"));
КонецПроцедуры
В данном случае мы используем объект ОформлениеСтроки, который содержит коллекцию Ячейки. Важно понимать: мы не меняем данные в базе, мы лишь управляем визуальным представлением конкретной строки. Метод УстановитьТекст() позволяет вывести строковое представление числа, которое останется видимым даже после выхода из режима редактирования.
Если для расчета данных в колонке требуется обращение к базе данных (например, получение остатков товаров на складе), использовать ПриВыводеСтроки крайне не рекомендуется. Это приведет к тому, что при прокрутке списка форма начнет "тормозить", так как запросы будут выполняться для каждой строки отдельно. В таких случаях мы используем событие ПриПолученииДанных.
Этот обработчик получает на вход сразу массив строк, которые платформа планирует отобразить на экране. Рассмотрим, как это работает на практике:
Процедура ТабличнаяЧастьПриПолученииДанных(Элемент, ОформленияСтрок)
// Подготовим список товаров для пакетного запроса
СписокТоваров = Новый СписокЗначений;
Для Каждого Оформление Из ОформленияСтрок Цикл
СписокТоваров.Добавить(Оформление.ДанныеСтроки.Номенклатура);
КонецЦикла;
// Выполняем ОДИН запрос для получения всех нужных данных
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Номенклатура, Остаток ИЗ Регистр.Остатки ГДЕ Номенклатура В (&Список)";
Запрос.УстановитьПараметр("Список", СписокТоваров);
Выборка = Запрос.Выполнить().Выбрать();
// Распределяем полученные данные по ячейкам
Пока Выборка.Следующий() Цикл
Для Каждого Оформление Из ОформленияСтрок Цикл
Если Оформление.ДанныеСтроки.Номенклатура = Выборка.Номенклатура Тогда
Оформление.Ячейки.ОстатокНаСкладе.УстановитьТекст(Выборка.Остаток);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Используя этот метод, мы существенно повышаем производительность приложения. Платформа вызывает этот код один раз для всей видимой области таблицы.
Рассмотрим ситуацию: пользователь изменил количество в строке. Мы ожидаем, что наша расчетная колонка тут же обновится. Однако события оформления (ПриВыводеСтроки) могут не сработать мгновенно. Чтобы заставить платформу перерисовать расчетную ячейку, в обработчике события ПриИзменении основной колонки необходимо вызвать метод обновления строк.
Процедура ТабличнаяЧастьКоличествоПриИзменении(Элемент)
// Принудительно вызываем перерисовку текущей строки
ЭлементыФормы.ТабличнаяЧасть.ОбновитьСтроки(ЭлементыФормы.ТабличнаяЧасть.ТекущаяСтрока);
КонецПроцедуры
Метод ОбновитьСтроки() сообщает системе, что визуальное состояние таблицы изменилось, и инициирует вызов обработчиков оформления. Без этого вызова пользователь увидит новый результат расчета только после того, как "дернет" таблицу мышкой или прокрутит список.
Проанализируем слабые стороны данного подхода, которые нужно учитывать при проектировании системы:
ОформлениеСтроки.Если эти ограничения критичны, рекомендуется рассмотреть альтернативный вариант: использовать в качестве источника данных формы не ТабличнуюЧасть объекта, а Таблицу Значений. В Таблице Значений можно создавать полноценные колонки, которые будут вести себя как обычные реквизиты (с сортировкой и поиском), но при этом не будут требовать изменения структуры метаданных в конфигураторе.
Таким образом, мы выяснили, что для простого визуального отображения расчетов лучше всего подходят события оформления строк. Мы научились правильно использовать УстановитьТекст() и поняли важность вызова ОбновитьСтроки() для поддержания актуальности данных в интерфейсе.