Каждый разработчик 1С рано или поздно сталкивается с загадочной ситуацией: пользователь открывает документ, ничего в нем не меняет, но в заголовке формы сразу появляется символ «*» (звездочка), а при попытке закрытия система настойчиво предлагает сохранить изменения. Это состояние называется модифицированностью. В данной статье мы подробно разберем, почему это происходит, где «прячется» причина, если отладчик молчит, и какими методами можно вычислить виновника программного изменения данных.
Прежде всего, нам необходимо разграничить два понятия: Модифицированность формы и Модифицированность самого объекта. В управляемом приложении за визуальную «звездочку» отвечает свойство формы. Однако важно понимать, что признак изменения формы может взводиться не только при редактировании данных пользователем, но и программно.
Рассмотрим ситуацию: в коде формы выполняется присвоение значения какому-либо реквизиту. Даже если новое значение совпадает с тем, что уже было в базе, платформа в некоторых случаях может расценить это как попытку записи и пометить форму как измененную. Проанализируем основные причины этого поведения.
Если стандартная проверка через отладчик в процедуре ПриОткрытии не дает результатов и значение ЭтаФорма.Модифицированность кажется неизменным, воспользуемся проверенным практикой методом последовательного исключения кода. Разберем этот алгоритм по шагам:
ПриОткрытии() (для обычных форм) или ПриСозданииНаСервере() и ПриЧтенииНаСервере() (для управляемых форм).Этот кропотливый, но эффективный метод позволяет точно локализовать строку, после исполнения которой объект считается измененным. Как отмечают опытные разработчики, часто проблема кроется в заполнении каких-то служебных реквизитов, которые не видны пользователю, но влияют на статус документа.
Проанализируем классическую ошибку, упомянутую в обсуждении: изменение данных без проверки на то, является ли документ новым. Выясним причину, почему это плохо. Рассмотрим пример кода, который часто приводит к нежелательной модифицированности:
Процедура ПриОткрытии()
// ОШИБКА: Реквизит меняется при каждом открытии,
// даже если документ уже был проведен и закрыт.
Ответственный = ПараметрыСеанса.ТекущийПользователь;
КонецПроцедуры
Чтобы избежать появления «звездочки» в уже существующих документах, необходимо всегда добавлять проверку на новизну объекта. Перепишем код правильно:
Процедура ПриОткрытии()
Если ЭтоНовый() Тогда
Ответственный = ПараметрыСеанса.ТекущийПользователь;
КонецЕсли;
КонецПроцедуры
В управляемых формах аналогичная логика должна применяться в событии ПриСозданииНаСервере, где мы проверяем Объект.Ссылка.Пустая().
Иногда код кажется чистым, но модифицированность все равно возникает. Выясним, какие неочевидные факторы на это влияют:
Модифицированность.В управляемых формах крайне важно проверить обработчик ПриЧтенииНаСервере. Это событие происходит до того, как управление передается в ПриСозданииНаСервере или ПриОткрытии на клиенте. Если в этом обработчике происходит расчет каких-то итогов или заполнение дополнительных колонок табличной части, которые связаны с данными объекта, форма сразу станет «грязной».
Посмотрим на пример, как можно отловить момент изменения свойства. Используйте «Остановку по условию» в отладчике или добавьте в подозрительные места следующий фрагмент:
Если ЭтаФорма.Модифицированность Тогда
// Здесь ставим точку останова
Сообщить("Форма изменена!");
КонецЕсли;
Разберем еще одну ситуацию: наличие «мусорных» данных в табличных частях. Иногда при открытии формы срабатывает инициализация строк. Если в табличной части есть скрытые колонки, которые заполняются значениями по умолчанию программно, и эти значения отличаются от физически записанных в базе (например, 0 вместо NULL), платформа пометит документ как измененный.
Для диагностики рекомендуем программно сравнить текущее состояние объекта с его версией в базе данных. Проанализируем, как это можно сделать в коде:
// Пример сравнения реквизита в форме и в базе
ОбъектВБазе = Объект.Ссылка.ПолучитьОбъект();
Для каждого Реквизит Из Объект.Метаданные().Реквизиты Цикл
Имя = Реквизит.Имя;
Если Объект[Имя] <> ОбъектВБазе[Имя] Тогда
Сообщить("Изменен реквизит: " + Имя);
КонецЕсли;
КонецЦикла;
Подведем итог: появление «звездочки» при открытии — это всегда результат несовпадения данных в оперативной памяти (в форме) и данных, считанных из базы. Основными инструментами борьбы с этим являются внимательный анализ событий инициализации формы и использование проверок на новизну объекта перед любым программным присваиванием значений реквизитам. Если стандартная отладка не помогает, используйте метод последовательного комментирования кода, чтобы найти ту самую строку, которая «тихо» меняет состояние документа.