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

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

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

Суть проблемы

Представим типичную ситуацию: у нас есть форма документа с табличной частью. Мы создаем команду (кнопку), которая должна заполнить эту табличную часть данными (иногда требуется программное создание колонок) на основе какого-то алгоритма или запроса. Код выполняется, данные в таблице визуально появляются, но если пользователь попытается закрыть форму сразу после этого, платформа закроет окно без предупреждения "Данные были изменены. Сохранить изменения?".

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

Почему платформа "молчит"?

В управляемом приложении работа с данными разделена на клиентскую и серверную части, а также на данные объекта и данные формы. Когда пользователь вводит данные с клавиатуры (интерактивно), платформа четко отслеживает эти действия и автоматически устанавливает признак модифицированности формы (появляется "звездочка" в заголовке).

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

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

Решение №1: Использование свойств команды (Рекомендуемый способ)

Самый правильный и "архитектурный" способ решения этой проблемы кроется не в написании дополнительного кода, а в настройке свойств самой команды формы.

Давайте рассмотрим свойства команды, которая привязана к кнопке на вашей форме. В палитре свойств (Properties) существует специальный флаг (булево свойство).

Свойство: Изменяет сохраняемые данные (ModifiesSavedData)

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

Чтобы исправить ситуацию, нам необходимо:

  1. Открыть форму документа в конфигураторе.
  2. Перейти на вкладку "Команды".
  3. Найти команду, которая выполняет программное изменение данных (заполнение табличной части).
  4. В палитре свойств установить галочку напротив свойства Изменяет сохраняемые данные.

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

Решение №2: Программная установка модифицированности

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

Для этого используется свойство управляемой формы Модифицированность.

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

Код серверной процедуры изменения данных (примерная структура):


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

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

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


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

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

Важный нюанс: Модифицированность Формы vs Модифицированность Объекта

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

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

В контексте управляемой формы мы работаем с ДанныеФормыСтруктура (реквизит Объект на форме). При работе на клиенте мы не имеем прямого доступа к методу Модифицированность() самого прикладного объекта. Интерфейсные механики 1С завязаны именно на свойство формы.

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

Выводы и рекомендации

Подводя итог, можно выделить следующее:

Следуя этим простым правилам, вы обеспечите предсказуемое поведение интерфейса и убережете пользователей от случайной потери данных.

← На главную