Почему при программном изменении реквизита в «ПриСозданииНаСервере()» не взводится модифицированность формы и как это исправить?

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

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

Выясняем причину: почему не возникает модифицированность?

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

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

Если же изменение данных происходит программно в коде модуля формы (например, конструкция вида Объект.МойРеквизит = Справочники.МойСправочник.ПустаяСсылка()), автоматического взвода флага модифицированности не происходит. Платформа «считает», что если разработчик делает это кодом, то он полностью контролирует жизненный цикл объекта и сам должен управлять состоянием формы.

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

Также важно различать, какой именно реквизит мы меняем. Проанализируем два сценария:

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

---

Вариант решения №1. Перенос инициализации в модуль объекта (Best Practice для новых объектов)

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

Разберем по шагам, как это реализовать:

  1. Откройте конфигуратор и перейдите в модуль нужного вам прикладного объекта (документа или справочника).
  2. Найдите или создайте предопределенную процедуру ОбработкаЗаполнения().
  3. Напишите код инициализации реквизитов.

Рассмотрим пример кода в модуле объекта:


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

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

Почему этот подход является наиболее правильным:

---

Вариант решения №2. Принудительная установка модифицированности (Для существующих объектов)

Что делать, если бизнес-логика требует очищать или изменять реквизиты уже записанного документа непосредственно при его открытии в форме? В этом случае использование ОбработкаЗаполнения() не поможет, и нам придется вносить изменения в модуль управляемой формы.

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

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	// Выполняем нашу бизнес-логику при определенных условиях
	Если Параметры.Свойство("ТребуетсяОчиститьРеквизит") И Параметры.ТребуетсяОчиститьРеквизит Тогда
		
		// Программное изменение реквизита объекта на сервере
		Объект.МойРеквизит = Справочники.МойСправочник.ПустаяСсылка();
		
		// Явно взводим флаг модифицированности формы
		ЭтаФорма.Модифицированность = Истина;
		
	КонецЕсли;

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

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

---

Важные технические нюансы работы с модифицированностью в УФ

При работе с модифицированностью управляемых форм крайне важно держать в уме несколько особенностей платформы «1С:Предприятие»:

  1. Свойство элементов формы «Изменяет сохраняемые данные»:

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

  2. Коварство функции «РеквизитФормыВЗначение()»:

    Иногда разработчики пытаются проверить, изменился ли прикладной объект на сервере с помощью вызова:

    ОбъектПрикладной = РеквизитФормыВЗначение("Объект");

    И затем делают проверку:

    Если ОбъектПрикладной.Модифицированность() Тогда ...

    Запомните: в управляемых формах метод Модифицированность() для объекта, полученного через РеквизитФормыВЗначение(), всегда будет возвращать значение Истина! Это связано с тем, что при конвертации данных формы в прикладной объект в оперативной памяти заново создается экземпляр объекта, и платформа превентивно считает его измененным. Для реального сравнения изменений вам придется писать собственные процедуры, сравнивающие текущие данные формы с данными, записанными в базе данных.

Таким образом, мы детально разобрали проблему сброса модифицированности при открытии формы. Всегда стремитесь использовать правильные обработчики событий: для заполнения новых объектов применяйте ОбработкаЗаполнения() в модуле объекта, а для изменения существующих данных в форме — не забывайте явно указывать ЭтаФорма.Модифицированность = Истина;.

← На главную