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

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

Работая с управляемыми формами в 1С, программисты часто сталкиваются с необходимостью динамического изменения интерфейса. Одним из таких сценариев является добавление новых колонок в уже существующий динамический список. Мы рассмотрим, как это сделать программно, особенно когда требуется вывести данные, полученные из модифицированного запроса к источнику данных списка.

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

Где размещать программный код для добавления колонок?

Критически важно понимать, что все операции по созданию и изменению элементов управляемой формы должны выполняться на стороне сервера. Наиболее подходящим местом для таких действий при инициализации формы является процедура ПриСозданииНаСервере(). Мы не будем использовать клиентские процедуры, такие как ПриОткрытии(), поскольку они не предназначены для манипулирования структурой формы.

Модификация запроса динамического списка

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

  1. Прямое изменение свойства ТекстЗапроса: Для относительно простых запросов, которые не содержат сложных конструкций (например, временных таблиц или множественных объединений), мы можем напрямую модифицировать свойство ТекстЗапроса динамического списка. Мы должны вставить в существующий текст запроса выборку нового поля с необходимыми данными.

  2. Использование объекта СхемаЗапроса для сложных случаев: Если запрос динамического списка является сложным, содержит временные таблицы, объединения или другие продвинутые конструкции, ручная модификация строки запроса может быть затруднительной и подверженной ошибкам. В таких случаях мы рекомендуем использовать объект СхемаЗапроса. Он позволяет нам:

    1. Загрузить существующий текст запроса динамического списка с помощью метода СхемаЗапроса.УстановитьТекстЗапроса().

    2. Программно добавить новые поля в коллекцию ВыбираемыеПоля соответствующего оператора выборки. Обычно это первый оператор в первом пакете запросов (например, СхемаЗапроса.ПакетЗапросов[0].Операторы[0].ВыбираемыеПоля).

    3. Получить модифицированный текст запроса с помощью метода СхемаЗапроса.ПолучитьТекстЗапроса().

    4. Присвоить полученный текст свойству ТекстЗапроса динамического списка.

    Ключевой момент: Мы должны убедиться, что новое поле в запросе имеет уникальный псевдоним (например, КурсыВалют.Курс КАК КурсВалюты), который мы затем будем использовать для привязки к элементу формы.

Программное добавление элемента формы для новой колонки

После того как запрос динамического списка обновлен и содержит необходимые данные, следующим шагом является программное добавление нового элемента формы типа ПолеФормы, которое будет представлять нашу новую колонку.

  1. Метод добавления: Мы используем метод Элементы.Добавить() коллекции элементов формы. Если нам нужно вставить колонку в определенное место (например, между существующими колонками), мы можем использовать метод Элементы.Вставить(), указав индекс.

  2. Ключевые свойства новой колонки: При добавлении нового поля нам необходимо установить следующие ключевые свойства:

    • Имя: Это уникальное имя для нового элемента на форме. Например, "СписокКурсВалюты". Важно, чтобы имя было уникальным в рамках коллекции элементов формы.

    • Тип: Всегда устанавливаем Тип("ПолеФормы"), поскольку мы добавляем именно поле формы.

    • Родитель: Указывает, к какому элементу формы принадлежит новая колонка. В нашем случае это сам элемент динамического списка. Если наш динамический список на форме называется "Список", то родителем будет Элементы.Список.

    • Вид: Определяет, как будет выглядеть колонка и какие данные она будет отображать. Например, ВидПоляФормы.ПолеВвода подходит для текстовых, числовых или строковых данных. Для булевых значений используем ВидПоляФормы.ПолеФлажка.

    • ПутьКДанным: Это одно из самых важных свойств. Оно должно указывать на путь к данным в динамическом списке, который соответствует полю, добавленным в запросе. Если в запросе мы добавили поле с псевдонимом "КурсВалюты", то ПутьКДанным будет выглядеть как "ИмяДинамическогоСписка.КурсВалюты" (например, "Список.КурсВалюты").

    • Заголовок: Это текст, который будет отображаться в шапке новой колонки на форме. Например, "Курс валюты".

Пример программного кода

Рассмотрим комплексный пример программного кода, который мы разместим в процедуре ПриСозданииНаСервере() формы. Этот пример демонстрирует как модификацию запроса, так и программное добавление новой колонки.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Определим имя нашего динамического списка на форме
    Перем ИмяДинамическогоСписка;
    ИмяДинамическогоСписка = "СписокЗаказов"; // Предположим, наш динамический список называется "СписокЗаказов"
    
    // Получаем ссылку на элемент динамического списка
    Перем ДинамическийСписокЭлемент;
    ДинамическийСписокЭлемент = Элементы[ИмяДинамическогоСписка];

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

    // Добавляем новое поле "Курс" из регистра сведений.
    // Находим первый оператор выбора в первом пакете запросов.
    Перем ОператорВыбора;
    ОператорВыбора = СхемаЗапросаОбъект.ПакетЗапросов[0].Операторы[0];
    ОператорВыбора.ВыбираемыеПоля.Добавить("КурсыВалют.Курс КАК КурсВалюты");
    
    // Присваиваем модифицированный текст запроса динамическому списку
    ДинамическийСписокЭлемент.ТекстЗапроса = СхемаЗапросаОбъект.ПолучитьТекстЗапроса();
    
    // 2. Добавляем новый элемент формы для отображения колонки
    Перем НоваяКолонка;
    НоваяКолонка = Элементы.Добавить("СписокЗаказовКурсВалюты", Тип("ПолеФормы"), ДинамическийСписокЭлемент);
    
    // Устанавливаем базовые свойства новой колонки
    НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
    НоваяКолонка.ПутьКДанным = ИмяДинамическогоСписка + ".КурсВалюты"; // "КурсВалюты" - это псевдоним поля в запросе
    НоваяКолонка.Заголовок = "Курс валюты";
    НоваяКолонка.Ширина = 12; // Установим ширину колонки
    НоваяКолонка.ТолькоПросмотр = Истина; // Сделаем поле только для чтения
    НоваяКолонка.ЧередоватьЦветаСтрок = Истина; // Для наглядности отображения

    // Если требуется вставить колонку в определенное место, например, после колонки "ВалютаНазвание":
    Перем ИндексВалютыНазвание;
    ИндексВалютыНазвание = -1;
    Для Каждого ЭлементСписка Из ДинамическийСписокЭлемент.ПодчиненныеЭлементы Цикл
        Если ЭлементСписка.ПутьКДанным = ИмяДинамическогоСписка + ".ВалютаНазвание" Тогда
            ИндексВалютыНазвание = ДинамическийСписокЭлемент.ПодчиненныеЭлементы.Индекс(ЭлементСписка);
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если ИндексВалютыНазвание <> -1 Тогда
        // Удалим ранее созданную колонку, чтобы добавить ее заново в нужное место
        Элементы.Удалить(НоваяКолонка);
        // Добавим колонку после "ВалютаНазвание" (индекс + 1)
        НоваяКолонка = Элементы.Вставить("СписокЗаказовКурсВалюты", Тип("ПолеФормы"), ДинамическийСписокЭлемент, ИндексВалютыНазвание + 1);
        
        // Заново устанавливаем свойства, так как это новый элемент
        НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
        НоваяКолонка.ПутьКДанным = ИмяДинамическогоСписка + ".КурсВалюты";
        НоваяКолонка.Заголовок = "Курс валюты";
        НоваяКолонка.Ширина = 12;
        НоваяКолонка.ТолькоПросмотр = Истина;
        НоваяКолонка.ЧередоватьЦветаСтрок = Истина;
    КонецЕсли;
    
КонецПроцедуры

Важные нюансы и рекомендации

  1. Связь полей запроса и колонок формы: Мы должны всегда помнить, что состав колонок и их настройки в динамическом списке тесно связаны с полями запроса по их псевдонимам. Если мы изменим псевдоним поля в запросе или поле вовсе исчезнет из запроса, то элемент формы, привязанный к этому ПутьКДанным, "потеряет" отображаемые данные или может привести к ошибкам выполнения.

  2. Производительность: Использование сложных запросов, особенно с множественными соединениями или подзапросами, в динамических списках может существенно влиять на производительность формы. Динамический список обновляется в реальном времени, и каждый раз выполняется его запрос. Мы должны стремиться к максимальной оптимизации запросов, чтобы избежать замедлений в работе пользовательского интерфейса, особенно при работе с большими объемами данных.

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

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

← На главную