Как программно поставить галочку «Использовать всегда» для реквизита формы в 1С?

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

При разработке на платформе 1С:Предприятие 8.3 в режиме управляемых форм программисты часто сталкиваются с необходимостью динамического изменения интерфейса. Типичная задача — программно добавить новую колонку (реквизит) в существующую табличную часть документа непосредственно во время работы приложения. Это позволяет выводить вспомогательную или расчетную информацию без изменения структуры метаданных самой конфигурации. Практические приёмы такой работы демонстрирует обработка с примером динамического создания и удаления элементов формы.

Однако при попытке связать программно созданный элемент формы с новым путем к данным разработчики нередко натыкаются на труднообъяснимую ошибку: «Ошибка при установке значения атрибута контекста (ПутьКДанным)» по причине: Недопустимое значение. Выясним причину этого поведения платформы и детально разберем рабочие способы решения проблемы.

Почему возникает ошибка «Недопустимое значение»?

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

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

В момент выполнения строки кода, связывающей элемент формы с данными:

НовыйЭлементФормы.ПутьКДанным = "Объект.ДанныеОВремени.ВремяИтогСтарое";

Платформа генерирует исключение, поскольку указанный путь к данным считается недоступным для клиентской части формы из-за оптимизации.

Ошибочный путь: Метод УстановитьОбязательноеИспользование()

Многие разработчики, пытаясь решить проблему программно, находят в синтакс-помощнике метод УстановитьОбязательноеИспользование(). Однако попытка применить его к табличной части документа или к ее элементам на форме вызывает ошибку «Метод объекта не обнаружен».

Проанализируем эту ситуацию. Данный метод принадлежит исключительно классу ДанныеФормыСтруктураСДинамическимСписком (динамическим спискам). Для обычных табличных частей документов, которые на форме представлены типом ДанныеФормыКоллекция, этого метода не существует. Платформа 1С не предоставляет программного интерфейса для изменения свойства «Использовать всегда» у стандартных реквизитов формы в режиме выполнения (runtime).

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

Решение 1: Использование расширения конфигурации (Рекомендуемое)

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

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

  1. Откройте конфигуратор вашей базы данных и создайте новое расширение (или откройте существующее).
  2. Найдите в дереве метаданных конфигурации документ (например, Табель) и добавьте его форму в расширение.
  3. В редакторе формы расширения перейдите на вкладку «Реквизиты».
  4. Разверните дерево основного реквизита Объект и найдите вашу табличную часть (например, ДанныеОВремени).
  5. Откройте палитру свойств этой табличной части (нажмите F4).
  6. Найдите свойство «Использовать всегда» и установите для него значение «Авто» или «Истина».

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // Шаг 1. Создаем массив добавляемых реквизитов
    ДобавляемыеРеквизиты = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы(
        "ВремяИтогСтарое", 
        Новый ОписаниеТипов("Строка"), 
        "Объект.ДанныеОВремени", 
        "Время итог (старое)"
    );
    ДобавляемыеРеквизиты.Добавить(НовыйРеквизит);
    
    // Шаг 2. Изменяем структуру реквизитов формы
    ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
    
    // Шаг 3. Добавляем визуальный элемент на форму
    ЭлементТаблица = Элементы.ДанныеОВремени;
    НовыйЭлемент = Элементы.Добавить("ВремяИтогСтарое", Тип("ПолеФормы"), ЭлементТаблица);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
    НовыйЭлемент.ПутьКДанным = "Объект.ДанныеОВремени.ВремяИтогСтарое";
    НовыйЭлемент.ТолькоПросмотр = Истина;

КонецПроцедуры

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

Решение 2: Использование полностью программной таблицы значений (для внешних обработок)

Бывают ситуации, когда использование расширений невозможно — например, при разработке универсальной внешней обработки или отчета, которые должны запускаться в любой базе без предварительной настройки конфигурации. В этом случае мы не можем гарантировать, что у табличной части документа включено свойство «Использовать всегда».

Чтобы обойти это ограничение, мы можем применить архитектурный паттерн с использованием временной программной таблицы значений на форме. Рассмотрим этот алгоритм:

  1. При создании формы на сервере мы программно создаем новый реквизит формы с типом ТаблицаЗначений. Для полностью созданных в коде таблиц оптимизация «Использовать всегда» не накладывает ограничений на привязку путей к данным.
  2. Переносим структуру колонок из оригинальной табличной части Объект.ДанныеОВремени во вновь созданную таблицу значений и добавляем нашу пользовательскую колонку ВремяИтогСтарое.
  3. Заполняем созданную таблицу данными из реального документа.
  4. Скрываем оригинальный элемент формы (табличную часть) и выводим на форму нашу программную таблицу значений.
  5. Перед записью документа переносим измененные данные из программной таблицы обратно в оригинальную табличную часть объекта.

Рассмотрим пример реализации создания такой таблицы:


&НаСервере
Процедура ИнициализироватьПрограммнуюТаблицу()

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

КонецПроцедуры

Этот способ более трудоемок в реализации, так как требует дополнительно описывать процедуры синхронизации данных при записи (через вызов метода РеквизитФормыВЗначение) и обработку интерактивных действий пользователя. Однако он гарантирует 100% автономность работы вашего программного кода независимо от настроек метаданных основной конфигурации.

← На главную