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

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

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

Обращение к программно добавленным реквизитам формы

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

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

Предположим, мы добавляем реквизиты с именами типа "Сообщение1", "Сообщение2" и так далее. После того как мы добавили их с помощью процедуры ИзменитьРеквизиты, мы можем обратиться к каждому из них следующим образом:


// Пример добавления реквизитов на серверной процедуре (например, ПриСозданииНаСервере)

// 1. Подготавливаем массив для добавляемых реквизитов
МассивДобавляемыхРеквизитов = Новый Массив;
Счетчик = 0; // Инициализируем счетчик для уникальных имен

// 2. В цикле собираем информацию о будущих реквизитах и создаем объекты РеквизитФормы
Для каждого СтрокаЗначений из ТаблицаЗначений Цикл
    Счетчик = Счетчик + 1;
    ИмяНовогоРеквизита = "Сообщение" + Счетчик;
    // Создаем объект РеквизитФормы с динамическим именем и нужным типом (например, ФорматированныйДокумент)
    НовоеСообщение = Новый РеквизитФормы(ИмяНовогоРеквизита, Новый ОписаниеТипов("ФорматированныйДокумент"));
    МассивДобавляемыхРеквизитов.Добавить(НовоеСообщение);
КонецЦикла;

// 3. Вызываем ИзменитьРеквизиты один раз, после того как собрали все реквизиты в массив.
// Это критически важно для производительности.
Если МассивДобавляемыхРеквизитов.Количество() > 0 Тогда
    ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
КонецЕсли;

// 4. Теперь, когда реквизиты добавлены в структуру формы, мы можем присваивать им значения.
// Снова проходим по нашим данным или используем уже существующий контекст.
Счетчик = 0;
Для каждого СтрокаЗначений из ТаблицаЗначений Цикл
    Счетчик = Счетчик + 1;
    ИмяНовогоРеквизита = "Сообщение" + Счетчик;
    // Обращаемся к реквизиту по строковому имени через квадратные скобки
    ЭтаФорма[ИмяНовогоРеквизита] = СтрокаЗначений.СодержимоеСообщения; 
    // Предполагаем, что СтрокаЗначений.СодержимоеСообщения имеет тип ФорматированныйДокумент
КонецЦикла;

Здесь ЭтаФорма представляет собой текущий объект управляемой формы. Использование ЭтаФорма[ИмяНовогоРеквизита] позволяет динамически собрать имя реквизита и затем получить к нему доступ для присвоения значения. Важно отметить, что этот синтаксис доступен сразу после выполнения процедуры ИзменитьРеквизиты в серверном контексте формы. Некоторые разработчики могут задаться вопросом о возможности использования ЭтотОбъект.ВашПрограммноДобавленныйРеквизит, но это некорректно, поскольку ЭтотОбъект относится к основному объекту данных формы (если форма является формой объекта), а не к реквизитам самой формы, добавленным через ИзменитьРеквизиты.

Оптимизация производительности при программном добавлении реквизитов

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

  1. Единичный вызов ИзменитьРеквизиты:

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

    
    // НЕПРАВИЛЬНО (вызов ИзменитьРеквизиты в цикле):
    // Счетчик = 0;
    // Для каждого СтрокаЗначений из ТаблицаЗначений Цикл
    //     Счетчик = Счетчик + 1;
    //     НовоеСообщение = Новый РеквизитФормы("Сообщение"+Счетчик, Новый ОписаниеТипов("ФорматированныйДокумент"));
    //     МассивДляИзменения = Новый Массив; // Создание нового массива каждый раз
    //     МассивДляИзменения.Добавить(НовоеСообщение);
    //     ИзменитьРеквизиты(МассивДляИзменения); // МНОГОКРАТНЫЙ ВЫЗОВ - ПЛОХАЯ ПРОИЗВОДИТЕЛЬНОСТЬ
    // КонецЦикла;
    
    // ПРАВИЛЬНО (один вызов ИзменитьРеквизиты после сбора всех реквизитов):
    МассивДобавляемыхРеквизитов = Новый Массив;
    Для каждого СтрокаЗначений из ТаблицаЗначений Цикл
        // ... создаем НовоеСообщение ... (как в примере выше)
        МассивДобавляемыхРеквизитов.Добавить(НовоеСообщение);
    КонецЦикла;
    Если МассивДобавляемыхРеквизитов.Количество() > 0 Тогда
        ИзменитьРеквизиты(МассивДобавляемыхРеквизитов); // ЕДИНСТВЕННЫЙ ВЫЗОВ - ОПТИМАЛЬНО
    КонецЕсли;
    
  2. Влияние количества реквизитов и их типа:

    Даже при однократном вызове ИзменитьРеквизиты, если мы добавляем очень большое количество реквизитов (сотни и более), это может сказаться на времени открытия и отклика формы. Каждый реквизит требует соответствующих элементов управления на форме для отображения (например, текстовое поле, поле форматированного документа и т.д.), что увеличивает объем данных для отрисовки в браузере или тонком клиенте.

    Особенно это актуально для реквизитов сложного типа, таких как ФорматированныйДокумент. Отображение большого числа полей с форматированным текстом может быть очень ресурсоемким, поскольку каждый такой элемент может содержать значительный объем данных и требует сложной отрисовки. Автор исходной темы столкнулся именно с этой проблемой, когда пытался отобразить много ФорматированныйДокумент, и в конечном итоге отказался от такого подхода из-за тормозов.

  3. Замеры производительности:

    Если мы подозреваем проблемы с производительностью, всегда необходимо использовать встроенные инструменты замера производительности 1С:Предприятия. Они позволяют точно определить, какие участки кода занимают больше всего времени выполнения. Это поможет нам локализовать "узкие места" и принять обоснованные решения по оптимизации, а не действовать наугад.

    Как показывает практика, сам по себе вызов ИзменитьРеквизиты для небольшого числа реквизитов занимает относительно небольшую долю общего времени открытия формы (например, 3-5%). Однако, если речь идет о сотнях реквизитов, суммарное время на их создание и, главное, отрисовку соответствующих элементов управления может стать критическим. Замеры помогут нам отличить проблемы с добавлением реквизитов от проблем с отрисовкой элементов или с работой другого кода.

Альтернативные подходы для отображения множества форматированных документов

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

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

    Вместо того чтобы создавать отдельный реквизит и соответствующий элемент управления для каждого форматированного документа, мы можем разместить на форме один элемент типа ПолеФорматированногоДокумента (или ПолеHTMLДокумента, если содержимое можно представить в HTML). Когда пользователь выбирает строку в таблице значений, динамическом списке или другом списке, мы присваиваем содержимое выбранного элемента этому единственному полю. Таким образом, у нас на форме всегда присутствует только один сложный элемент для отрисовки, что значительно экономит ресурсы и улучшает скорость отклика.

    
    // Пример:
    // У нас есть реквизит формы "ТаблицаСообщений" типа ТаблицаЗначений,
    // содержащий колонку "Сообщение" типа ФорматированныйДокумент.
    // На форме создан элемент "ПолеДетальногоСообщения" с видом "Поле форматированного документа"
    // и связанный с реквизитом формы (например, просто для инициализации).
    
    &НаКлиенте
    Процедура ТаблицаСообщенийПриАктивизацииСтроки(Элемент)
        Если Элемент.ТекущиеДанные <> Неопределено Тогда
            // При активации строки, присваиваем содержимое колонки "Сообщение"
            // нашему единственному элементу ПолеДетальногоСообщения
            ЭтаФорма.Элементы.ПолеДетальногоСообщения.Значение = Элемент.ТекущиеДанные.Сообщение;
        Иначе
            // Если строка не выбрана, очищаем поле
            ЭтаФорма.Элементы.ПолеДетальногоСообщения.Значение = Новый ФорматированныйДокумент();
        КонецЕсли;
    КонецПроцедуры;
    

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

  2. Использование ТабличногоПоля с возможностью пользовательского вывода (ограниченные возможности):

    Хотя напрямую поместить ФорматированныйДокумент в колонку табличного поля управляемой формы нельзя, мы можем использовать табличное поле с источником данных типа ДинамическийСписок или ТаблицаЗначений для отображения списка элементов. Для доступа к форматированному содержимому можно рассмотреть следующие варианты, хотя они не всегда удовлетворяют всем требованиям к отображению:

    • Вывод HTML в ячейке: Если форматирование можно упростить до HTML-разметки, и в платформе есть возможности для вывода HTML в ячейках (это зависит от версии и режима совместимости платформы, и не является стандартной функциональностью для ФорматированныйДокумент), это может быть опцией. Однако это потребует предварительного преобразования ФорматированныйДокумент в HTML.
    • Кнопка "Подробнее" или всплывающее окно: В каждой строке табличного поля можно добавить командную кнопку, например, с текстом "Подробнее". По нажатию на эту кнопку будет открываться отдельная вспомогательная форма или всплывающая панель, содержащая один элемент типа ПолеФорматированногоДокумента, куда и будет загружаться полное содержимое ФорматированныйДокумент для выбранной строки. Это позволяет эффективно управлять ресурсами, загружая сложный элемент только по требованию.
  3. Ленивая загрузка (Lazy Loading):

    Если нам действительно нужно отобразить очень много форматированных документов, и их количество не позволяет создать все элементы сразу, мы можем использовать принцип ленивой загрузки (Lazy Loading). Например, отображать только первые N документов, а остальные подгружать по мере прокрутки табличного поля или по требованию пользователя. Это сложнее в реализации, так как требует дополнительной логики для управления видимостью и подгрузкой данных, но позволяет эффективно управлять нагрузкой на форму и сервер.

Заключение

В ходе нашего анализа мы выяснили, что для обращения к программно добавленным реквизитам управляемой формы в 1С 8.3 следует использовать синтаксис ЭтаФорма[ИмяРеквизитаСтрокой]. Это позволяет динамически формировать имена реквизитов и успешно с ними работать в серверном контексте. При этом крайне важно вызывать процедуру ИзменитьРеквизиты только один раз после формирования полного списка добавляемых реквизитов, чтобы минимизировать накладные расходы и избежать проблем с производительностью.

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

← На главную