Разработка интерфейсов на управляемых формах в 1С имеет свою важную специфику. В отличие от обычных форм, где данные и их визуальное представление были жестко связаны, в управляемом приложении действует строгий принцип разделения данных и интерфейса. Из-за этого разработчики часто сталкиваются с проблемой: при попытке загрузить результат произвольного запроса в таблицу на форме она либо остается пустой, либо платформа выдает ошибки.
В этой статье мы подробно разберем, как правильно решать эту задачу. Мы рассмотрим два основных сценария: программное создание колонок для Таблицы Значений на форме и использование более производительной альтернативы — Динамического списка. Мы выясним особенности каждого подхода, проанализируем возможные ошибки и напишем готовые шаблоны кода.
Давайте разберем типичную ситуацию. Нам необходимо вывести результат запроса в таблицу на управляемой форме. На форме мы создали реквизит с типом ТаблицаЗначений (например, с именем ТЗДляВыгрузки) и разместили его на форме как элемент управления «Таблица».
Если мы попытаемся выполнить привычный для обычных форм код:
ТЗ_Результат = Запрос.Выполнить().Выгрузить();
ТЗДляВыгрузки.Загрузить(ТЗ_Результат);
Элементы.ТЗДляВыгрузки.СоздатьКолонки();
то мы столкнемся с тем, что таблица на форме останется пустой или платформа вернет ошибку о том, что объект не обнаружен. Выясним причину этого поведения. Метод СоздатьКолонки() у элемента формы действительно существует, но он умеет визуализировать только те колонки, которые уже явно объявлены в структуре реквизита формы. Если сам реквизит ТЗДляВыгрузки изначально не имеет колонок в конфигураторе, метод просто не сможет ничего отобразить.
Для того чтобы таблица корректно отобразила новые данные, нам придется полностью пересоздать структуру реквизита на сервере и затем программно добавить элементы формы. Для этой задачи можно использовать обработку с примером динамического добавления и удаления элементов формы.
Рассмотрим по шагам детальный алгоритм, как полностью программно воссоздать структуру таблицы значений под результат любого запроса. Весь процесс должен происходить исключительно в серверном контексте.
ИзменитьРеквизиты(). Мы подготавливаем массив новых реквизитов.ИзменитьРеквизиты().ЗначениеВРеквизитФормы().ПолеФормы и связываем их с данными.Посмотрим на пример готовой процедуры, реализующей этот алгоритм:
&НаСервере
Процедура ОбновитьТаблицуНаФорме(Запрос)
// Шаг 1. Получаем таблицу значений из запроса
ТЗ_Результат = Запрос.Выполнить().Выгрузить();
// Имя нашего реквизита на управляемой форме
ИмяРеквизитаТЗ = "ТЗДляВыгрузки";
// Шаг 2. Очищаем старые элементы формы (визуальные колонки)
ЭлементТаблица = Элементы[ИмяРеквизитаТЗ];
МассивКолонокДляУдаления = Новый Массив;
Для Каждого ТекЭлемент Из ЭлементТаблица.ПодчиненныеЭлементы Цикл
МассивКолонокДляУдаления.Добавить(ТекЭлемент);
КонецЦикла;
Для Каждого ТекЭлемент Из МассивКолонокДляУдаления Цикл
Элементы.Удалить(ТекЭлемент);
КонецЦикла;
// Шаг 3. Удаляем старые реквизиты из структуры формы
МассивРеквизитовДляУдаления = Новый Массив;
ТекущиеРеквизиты = ПолучитьРеквизиты(ИмяРеквизитаТЗ);
Для Каждого ТекРеквизит Из ТекущиеРеквизиты Цикл
МассивРеквизитовДляУдаления.Добавить(ИмяРеквизитаТЗ + "." + ТекРеквизит.Имя);
КонецЦикла;
// Шаг 4. Подготавливаем новые реквизиты на основе колонок результата запроса
МассивРеквизитовДляДобавления = Новый Массив;
Для Каждого Колонка Из ТЗ_Результат.Колонки Цикл
ОписаниеТипа = Колонка.ТипЗначения;
НовыйРеквизит = Новый РеквизитФормы(
Колонка.Имя,
ОписаниеТипа,
ИмяРеквизитаТЗ,
Колонка.Заголовок
);
МассивРеквизитовДляДобавления.Добавить(НовыйРеквизит);
КонецЦикла;
// Применяем изменения структуры формы на сервере
ИзменитьРеквизиты(МассивРеквизитовДляДобавления, МассивРеквизитовДляУдаления);
// Шаг 5. Заполняем форму данными из таблицы значений
ЗначениеВРеквизитФормы(ТЗ_Результат, ИмяРеквизитаТЗ);
// Шаг 6. Программно создаем новые визуальные элементы на форме
Для Каждого Колонка Из ТЗ_Результат.Колонки Цикл
ИмяЭлементаКолонки = ИмяРеквизитаТЗ + "_" + Колонка.Имя;
НоваяКолонка = Элементы.Добавить(ИмяЭлементаКолонки, Тип("ПолеФормы"), ЭлементТаблица);
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
// Связываем элемент с данными реквизита формы
НоваяКолонка.ПутьКДанным = ИмяРеквизитаТЗ + "." + Колонка.Имя;
НоваяКолонка.Заголовок = Колонка.Заголовок;
КонецЦикла;
КонецПроцедуры
Важный нюанс производительности: Метод ИзменитьРеквизиты() заставляет платформу полностью перестраивать контекст формы и передавать его между сервером и клиентом. Если вы будете вызывать эту процедуру слишком часто (например, при изменении параметров запроса пользователем), интерфейс может заметно «подвисать». Используйте этот способ взвешенно.
В ряде случаев гораздо более правильным решением с точки зрения архитектуры 1С является использование Динамического списка вместо ручной загрузки данных в Таблицу Значений.
Динамический список работает оптимально: он считывает данные из базы порциями по мере прокрутки таблицы пользователем. Это экономит оперативную память сервера и клиента. Более того, при использовании Динамического списка нам не требуется программно создавать колонки — платформа берет эту задачу на себя, предоставляя пользователю встроенные механизмы группировки, сортировки и условного оформления.
Выясним, как правильно передавать параметры в запрос динамического списка. Делать это нужно обязательно до открытия формы (например, в обработчике события ПриСозданииНаСервере), иначе платформа выдаст ошибку о незаполненных параметрах.
Рассмотрим пример установки параметров динамического списка:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Установка начальных значений параметров для динамического списка "ТЗДляВыгрузки"
ТЗДляВыгрузки.Параметры.УстановитьЗначениеПараметра("НачДата", Период.ДатаНачала);
ТЗДляВыгрузки.Параметры.УстановитьЗначениеПараметра("КонДата", Период.ДатаОкончания);
КонецПроцедуры
Если в процессе работы пользователю необходимо обновить данные по новым датам, мы можем вызвать этот же метод из любого другого серверного метода формы. Список автоматически обновит данные на клиенте.
При использовании Динамического списка разработчики часто сталкиваются с неочевидной деталью: порядок полей в тексте запроса (в секции ВЫБРАТЬ...) может не совпадать с порядком колонок на форме. Почему это происходит?
Дело в том, что порядок колонок в таблице формы для динамического списка определяется:
Если вам требуется гарантировать строгий порядок колонок программно, мы рекомендуем использовать метод элементов формы Переместить(). Посмотрим на пример вызова этого метода:
// Пример перемещения колонки "КоличествоОборот" в самое начало таблицы
Элементы.Переместить(Элементы.ТЗДляВыгрузкиКоличествоОборот, Элементы.ТЗДляВыгрузки);
Проанализируем ситуации, в которых следует выбирать каждый из подходов:
Выбирайте программную Таблицу Значений (ТЗ), если:
Выбирайте Динамический список (ДС), если:
Таким образом, сочетание этих двух подходов позволяет гибко решать любые задачи по выводу сложных запросов на управляемые формы в 1С 8.3.