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

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

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

Почему программно созданный реквизит формы не сохраняет значение

Для понимания проблемы проанализируем архитектуру управляемых форм платформы 1С:Предприятие 8.3:

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

Рассмотрим правильные подходы к реализации сохранения данных в зависимости от условий задачи.

Способ 1. Создание постоянного реквизита объекта с управлением видимостью

Если для бизнес-логики требуется хранить постоянное значение (например, ссылку на перечисление в справочнике «Внутренние документы»), самым надежным и производительным решением является добавление обычного реквизита в метаданные объекта.

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

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем условие, например значение реквизита вида документа
    НужноОтображатьРеквизит = ЗначениеЗаполнено(Объект.ВидДокумента) 
        И Объект.ВидДокумента.ТребуетсяДополнительнаяКлассификация;
        
    Элементы.РеквизитКлассификации.Видимость = НужноОтображатьРеквизит;
    
КонецПроцедуры

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

Способ 2. Использование штатного механизма дополнительных реквизитов (БСП / 1С:Документооборот)

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

  1. Перейдем в карточку справочника Виды внутренних документов в пользовательском режиме.
  2. В настройках вида документа перейдем на закладку, отвечающую за состав реквизитов.
  3. Добавим Дополнительный реквизит с нужным типом (например, ссылка на перечисление).

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

Способ 3. Хранение данных в регистре сведений с программным управлением на форме

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

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

  1. Создание реквизита и элемента формы: выполняем в процедуре ПриСозданииНаСервере.
  2. Чтение сохраненных данных: обязательно размещаем не только в ПриСозданииНаСервере, но и в ПриЧтенииНаСервере (это событие вызывается при повторном считывании данных и сразу после записи объекта).
  3. Запись данных: выполняем в транзакции записи объекта в обработчике ПередЗаписьюНаСервере.
  4. Отслеживание изменений: на клиенте при изменении элемента взводим признак модифицированности.

Посмотрим на пример программной реализации в модуле формы:


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

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // Обязательно перечитываем данные после перезаписи объекта
    ПрочитатьЗначениеИзРегистра();
КонецПроцедуры

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

&НаКлиенте
Процедура ПользовательскийРеквизитПриИзменении(Элемент)
    // Уведомляем форму об изменении данных, чтобы сработал запрос на сохранение при закрытии
    Модифицированность = Истина;
КонецПроцедуры

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

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

← На главную