Почему при закрытии документа 1С появляется сообщение «Данные были изменены», если ничего не менялось?

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

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

Даже если закомментировать стандартные обработчики инициализации ПередОткрытием и ПриОткрытии, проблема может сохраняться. Рассмотрим подробнее, почему платформа 1С считает документ измененным, как быстро локализовать источник проблемы и как правильно его устранить.

Главная причина: некорректная работа в обработчиках табличного поля

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

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

Посмотрим на типичный ошибочный код в модуле формы:


Процедура ТабличнаяЧастьТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    // ОШИБКА: Прямое присвоение значения реквизиту строки объекта!
    Если ДанныеСтроки <> Неопределено Тогда
        ДанныеСтроки.Сумма = ДанныеСтроки.Количество * ДанныеСтроки.Цена;
    КонецЕсли;
КонецПроцедуры

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

Другие скрытые причины ложной модифицированности

Если в процедуре ПриВыводеСтроки код отсутствует или закомментирован, но документ все равно помечается звездочкой, проанализируем другие характерные источники проблемы:

  1. Несовпадение типов реквизита и элемента управления. Если реквизит документа имеет составной тип или определенную разрядность числа, а поле ввода на форме жестко настроено на другой тип, платформа при открытии формы может автоматически выполнить неявное приведение типа. Такое приведение изменяет значение реквизита в памяти и делает форму модифицированной.
  2. События позиционирования табличного поля. При первоначальном выводе таблицы фокус автоматически устанавливается на первую строку. В этот момент неявно отрабатывают события ПриАктивизацииСтроки, ПриАктивизацииЯчейки и ПриСменеТекущейКолонки. Если в них зашито пересчитывание реквизитов формы или шапки документа, флаг модифицированности устанавливается сразу после отрисовки.
  3. Процедуры обновления отображения. Обработчик ОбновлениеОтображения вызывается платформой при любых изменениях в интерфейсе. Любые прямые манипуляции с реквизитами документа внутри этой процедуры приведут к бесконечной модификации данных.
  4. Фоновые механизмы и внешние события. Процедуры, вызываемые по таймеру через ПодключитьОбработчикОжидания(), либо обработка внешних сигналов в ОбработкаВнешнегоСобытия (например, от сканеров штрихкодов или торгового оборудования) могут модифицировать данные в скрытом режиме.
  5. Автоматическое восстановление настроек. Если для формы или элементов управления включены опции «СохранятьЗначение» и «ВосстанавливатьЗначения», автозаполнение сохраненных параметров может переписать текущие реквизиты объекта при инициализации формы.

Методы точной диагностики

Чтобы не гадать и не комментировать весь модуль формы наугад, разберем по шагам надежные методы поиска виновного участка кода:

  1. Точка останова по условию в отладчике. Это самый быстрый способ поймать момент изменения данных. Установим точку останова в самом начале работы формы (например, в процедуре ПередОткрытием) и в свойствах точки зададим условие: ЭтаФорма.Модифицированность = Истина. Запустим открытие документа. Как только любая строка кода или внутреннее событие переведет флаг модифицированности в значение «Истина», отладчик мгновенно остановит выполнение, и стек вызовов покажет точную процедуру.
  2. Трассировка через замер производительности. В конфигураторе перед открытием документа в режиме «1С:Предприятие» включим замер производительности (меню «Отладка» — «Замер производительности»), затем откроем проблемный документ и сразу остановим замер. В дереве вызовов проанализируем все процедуры модуля формы, которые выполнились при открытии, включая скрытые обработчики табличных полей.
  3. Проверка модифицированности объекта и формы. В табло отладчика можно проверить два выражения: ЭтаФорма.Модифицированность (состояние самой экранной формы) и ЭтотОбъект.Модифицированность() (состояние данных документа). Это помогает понять, изменился ли сам объект в памяти или только форма.

Способы решения и исправления ошибки

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

Способ 1. Использование объекта ОформлениеСтроки

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


Процедура ТабличнаяЧастьТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    Если ДанныеСтроки <> Неопределено Тогда
        // Правильно: изменяем только отображаемый текст в ячейке
        РасчетноеЗначение = ДанныеСтроки.Количество * ДанныеСтроки.Цена;
        ОформлениеСтроки.Ячейки.Сумма.УстановитьТекст(Строка(РасчетноеЗначение));
    КонецЕсли;
КонецПроцедуры

При таком подходе свойство ДанныеСтроки не модифицируется, значение в объект не записывается, и форма остается в исходном неизмененном состоянии.

Способ 2. Использование несвязанных колонок

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

Способ 3. Принудительный сброс признака модифицированности

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


Процедура ПриОткрытии()
    // Выполнение необходимых расчетов при открытии формы
    ЗаполнитьВспомогательныеДанные();
    
    // Снимаем признак модифицированности формы, 
    // чтобы при закрытии не появлялся запрос на сохранение
    ЭтаФорма.Модифицированность = Ложь;
КонецПроцедуры

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

← На главную