Как программно настроить динамический список в 1С: устанавливаем обязательное использование полей и добавляем новые колонки на форму

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработка интерфейсов на управляемых формах в «1С:Предприятие 8» часто требует от нас гибкости. Иногда стандартной интерактивной настройки динамического списка в конфигураторе недостаточно — например, когда логика отображения данных зависит от прав пользователя, настроек программы или нам необходимо доработать типовую форму в расширении без снятия с поддержки. В таких случаях на помощь приходит программная настройка динамического списка.

В рамках этой статьи мы детально разберем две практические задачи, с которыми часто сталкиваются разработчики:

  1. Как программно установить аналог флажка «Использовать всегда» для полей динамического списка.
  2. Как правильно изменить текст запроса динамического списка и вывести добавленные поля в качестве колонок на форму, избежав популярной ошибки «Путь к данным не найден».

---

Задача 1. Программная установка свойства «Использовать всегда»

Флаг «Использовать всегда» (в интерфейсе конфигуратора) указывает платформе, что данное поле должно обязательно выбираться из базы данных в SQL-запросе, даже если сама колонка скрыта пользователем на форме. Это критически важно, когда значение поля используется в условном оформлении списка, при активизации строки для каких-либо расчетов или при передаче данных на клиент.

Если нам необходимо установить это свойство программно, мы не найдем у полей динамического списка прямого свойства в стиле Поле.ИспользоватьВсегда = Истина. Вместо этого у самого объекта динамического списка существует специальный метод.

Разберем по шагам, как применить метод УстановитьОбязательноеИспользование(). Нам понадобятся имя реквизита динамического списка (обычно это Список) и имя поля из запроса.

Проанализируем пример кода, который необходимо разместить в обработчике события формы ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Устанавливаем обязательное получение поля "СтатусЗаказа" из базы данных
    Список.УстановитьОбязательноеИспользование("СтатусЗаказа", Истина);
    
    // Если в какой-то момент логики это свойство нужно отключить:
    // Список.УстановитьОбязательноеИспользование("СтатусЗаказа", Ложь);
    
КонецПроцедуры

Метод УстановитьОбязательноеИспользование() принимает два параметра:

---

Задача 2. Программное добавление полей запроса и вывод их на форму

Перейдем к более сложной задаче. Представим ситуацию: у нас есть динамический список, и нам нужно дополнить его запрос новыми данными (например, соединением с другим регистром или справочником), а затем вывести эти данные в таблицу на форме.

Типичная ошибка начинающих разработчиков заключается в попытке использовать метод формы ИзменитьРеквизиты(). Выясним причину, почему это не работает. Метод ИзменитьРеквизиты() предназначен исключительно для работы с собственными реквизитами управляемой формы (переменными, таблицами значений формы и т.д.). Поля динамического списка не являются реквизитами формы в классическом понимании платформы 1С. Их состав полностью определяется схемой компоновки данных или текстом SQL-запроса, который лежит в основе списка. Как только мы меняем текст запроса в свойстве Список.ТекстЗапроса, платформа автоматически обновляет структуру доступных полей списка.

Однако просто изменить текст запроса мало — колонка не появится на экране сама по себе. Нам нужно программно создать элемент формы (колонку таблицы) и правильно связать его с данными динамического списка.

Рассмотрим пошаговый алгоритм решения этой задачи в обработчике ПриСозданииНаСервере:


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

Обратите внимание на Шаг 3 и Шаг 4. Если вы попытаетесь добавить элемент формы просто в корень формы (передав третьим параметром ЭтотОбъект или опустив его), либо укажете неверный ПутьКДанным, платформа выдаст ошибку при запуске. Путь к данным обязательно должен ссылаться на реквизит списка через точку.

---

Профессиональный подход: Использование объекта «СхемаЗапроса»

Обычное текстовое сложение строк при изменении запроса (использование оператора + или функции СтрЗаменить()) — крайне нестабильный подход. Если вендор обновит конфигурацию и изменит структуру исходного запроса, ваш код автозамены строк может полностью сломаться.

Для надежного изменения динамического списка рекомендуется использовать объект СхемаЗапроса. Он парсит текст запроса в логическое дерево объектов, что позволяет безопасно внедрять новые поля, условия и соединения.

При работе со схемами запросов для динамических списков есть одна важнейшая деталь. Обязательно нужно устанавливать свойство схемы РежимКомпоновкиДанных в значение Истина. Если этого не сделать, при обратной сборке текста запроса "сломаются" инструкции системы компоновки данных (фигурные скобки вида {ГДЕ ...} или {ВЫБРАТЬ ...}), что приведет к неработоспособности пользовательских настроек и отборов в списке.

Посмотрим на пример применения схемы запроса:


&НаСервере
Процедура МодифицироватьЗапросЧерезСхему()
    
    Схема = Новый СхемаЗапроса;
    // Обязательно включаем режим компоновки данных для сохранения фигурных скобок СКД
    Схема.РежимКомпоновкиДанных = Истина; 
    
    // Загружаем исходный текст запроса динамического списка
    Схема.УстановитьТекстЗапроса(Список.ТекстЗапроса);
    
    // Получаем первый пакет и первую выборку запроса
    ПакетЗапроса = Схема.ПакетЗапросов[0];
    Выборка = ПакетЗапроса.Выборка[0];
    
    // Программно добавляем левое соединение и выбираем новые поля
    // (Детальный код настройки таблиц и связей опустим для краткости, 
    // схема запроса позволяет делать это через обращение к коллекциям операторов)
    
    // Возвращаем измененный текст обратно в список
    Список.ТекстЗапроса = Схема.ПолучитьТекстЗапроса();
    
КонецПроцедуры

---

Альтернатива: Использование события «ПриПолученииДанныхНаСервере»

Иногда добавление левых соединений (ЛЕВОЕ СОЕДИНЕНИЕ) в основной запрос списка существенно снижает производительность системы. Особенно это критично, если таблицы содержат миллионы записей, а СУБД (например, PostgreSQL) строит неоптимальные планы запросов.

В современных версиях платформы «1С:Предприятие» существует отличная альтернатива усложнению SQL-запроса — использование события таблицы списка ПриПолученииДанныхНаСервере.

Разберем этот метод по шагам:

  1. Мы добавляем на форму новую колонку в таблицу динамического списка, но ее свойство ПутьКДанным оставляем абсолютно пустым.
  2. Платформа выводит на экран только видимую часть строк (например, 30–40 строк, помещающихся на мониторе пользователя).
  3. В событии таблицы ПриПолученииДанныхНаСервере мы получаем доступ именно к этим видимым строкам. Мы можем сделать один быстрый и легкий точечный запрос к базе данных только по массиву ссылок отображаемых строк, получить нужные данные и заполнить ячейки динамически.

Проанализируем пример реализации данного подхода:


&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    
    // Соберем массив ссылок только тех строк, которые реально выводятся на экран в данный момент
    МассивСсылок = Новый Массив;
    Для Каждого СтрокаСписка Из Строки Цикл
        МассивСсылок.Добавить(СтрокаСписка.Ключ);
    КонецЦикла;
    
    Если МассивСсылок.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Выполняем быстрый запрос только по отобранным ссылкам
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ДопСведения.Объект КАК Объект,
        |   ДопСведения.СрокДоставки КАК СрокДоставки
        |ИЗ
        |   РегистрСведений.ДополнительныеСведения КАК ДопСведения
        |ГДЕ
        |   ДопСведения.Объект В (&МассивСсылок)";
        
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Заполняем данные непосредственно в оформление строк
    Пока Выборка.Следующий() Цикл
        СтрокаДанных = Строки[Выборка.Объект];
        Если СтрокаДанных <> Неопределено Тогда
            // Устанавливаем текст отображения в нашу пустую программную колонку
            СтрокаДанных.Данные["СписокСрокДоставки"].УстановитьТекст(Строка(Выборка.СрокДоставки) + " дн.");
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Этот способ позволяет избежать изменения структуры динамического списка и гарантирует максимальное быстродействие интерфейса программы, так как тяжелые расчеты или соединения выполняются порционно только для тех записей, которые видит пользователь.

← На главную