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