При разработке в среде "1С:Предприятие" на управляемых формах (где часто требуется добавление реквизитов и элементов) мы часто сталкиваемся с ситуациями, когда поведение платформы кажется нелогичным на первый взгляд. Одна из распространенных проблем, с которой сталкиваются разработчики, — отсутствие запроса на сохранение документа после того, как данные были изменены программно (например, по нажатию кнопки). В этой статье мы изучим приемы построения эффективных интерфейсов, разберем, почему так происходит и как устроена логика модифицированности формы.
Представим типичную ситуацию: у нас есть форма документа с табличной частью. Мы создаем команду (кнопку), которая должна заполнить эту табличную часть данными (иногда требуется программное создание колонок) на основе какого-то алгоритма или запроса. Код выполняется, данные в таблице визуально появляются, но если пользователь попытается закрыть форму сразу после этого, платформа закроет окно без предупреждения "Данные были изменены. Сохранить изменения?".
Это может привести к потере данных, так как пользователь уверен, что раз он видит изменения на экране, программа должна их отслеживать. Давайте разберем причины такого поведения.
В управляемом приложении работа с данными разделена на клиентскую и серверную части, а также на данные объекта и данные формы. Когда пользователь вводит данные с клавиатуры (интерактивно), платформа четко отслеживает эти действия и автоматически устанавливает признак модифицированности формы (появляется "звездочка" в заголовке).
Однако, когда изменения происходят программно (через код модуля формы), платформа по умолчанию считает, что разработчик контролирует процесс. Не всякое программное изменение реквизитов формы должно приводить к запросу на сохранение. Например:
Если бы платформа реагировала на каждое такое изменение установкой флага модифицированности, работа с программой стала бы невыносимой из-за постоянных лишних вопросов. Поэтому механизм автоматического взвода флага при программных изменениях отключен. Ответственность за это ложится на разработчика.
Самый правильный и "архитектурный" способ решения этой проблемы кроется не в написании дополнительного кода, а в настройке свойств самой команды формы.
Давайте рассмотрим свойства команды, которая привязана к кнопке на вашей форме. В палитре свойств (Properties) существует специальный флаг (булево свойство).
Свойство: Изменяет сохраняемые данные (ModifiesSavedData)
По умолчанию это свойство установлено в значение Ложь. Это означает, что платформа воспринимает команду как сервисную (например, печать, открытие отчета, калькулятор), которая не влияет на состояние данных объекта.
Чтобы исправить ситуацию, нам необходимо:
После этого, как только код команды будет успешно выполнен, платформа автоматически установит признак модифицированности для формы. Это вызовет появление "звездочки" в заголовке, и при попытке закрытия окна сработает стандартный механизм контроля записи.
Иногда бывают ситуации, когда логика сложнее, и мы не можем использовать свойство команды. Например, данные меняются не всегда, а только при выполнении определенного условия внутри кода. В этом случае мы можем управлять состоянием формы вручную.
Для этого используется свойство управляемой формы Модифицированность.
Рассмотрим пример кода, основанный на задаче автора. Допустим, у нас есть процедура заполнения данных дольщиков. В конце этой процедуры (на клиенте) нам нужно явно сообщить форме, что она была изменена.
Код серверной процедуры изменения данных (примерная структура):
&НаСервере
Процедура ЗаполнитьДанныеНаСервере()
// Получаем данные (имитация запроса из обсуждения)
РезультатЗапросаДольщики = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Объект.Договор, "Контрагенты");
// Очищаем или подготавливаем ТЧ
Объект.ДанныеДольщиков.Очистить();
// Обходим результаты и заполняем ТЧ
Для Каждого СтрокаТЧ Из РезультатЗапросаДольщики Цикл
// Добавление первой строки (ФИО)
НовСтр = Объект.ДанныеДольщиков.Добавить();
НовСтр.Дольщик = СтрокаТЧ.Контрагент;
НовСтр.ВидРеквизита = Перечисления.ВидыРеквизитов.ФИО;
// ... заполнение значений
// Добавление второй строки (Паспорт)
НовСтр = Объект.ДанныеДольщиков.Добавить();
НовСтр.Дольщик = СтрокаТЧ.Контрагент;
НовСтр.ВидРеквизита = Перечисления.ВидыРеквизитов.ПаспортСерия;
// ... заполнение значений
КонецЦикла;
КонецПроцедуры
Теперь обратим внимание на клиентскую часть, откуда вызывается этот код. Именно здесь нам нужно взвести флаг:
&НаКлиенте
Процедура Заполнить(Команда)
// Вызываем серверную логику изменения данных
ЗаполнитьДанныеНаСервере();
// Явно указываем, что форма модифицирована
ЭтаФорма.Модифицированность = Истина;
КонецПроцедуры
Используя конструкцию ЭтаФорма.Модифицированность = Истина, мы принудительно переводим форму в состояние "есть несохраненные изменения".
В процессе обсуждения данной темы важно понимать различие между двумя понятиями, которые часто путают новички:
ДокументОбъект). Он проверяет, отличается ли текущее состояние объекта в памяти от того, что записано в базе данных.В контексте управляемой формы мы работаем с ДанныеФормыСтруктура (реквизит Объект на форме). При работе на клиенте мы не имеем прямого доступа к методу Модифицированность() самого прикладного объекта. Интерфейсные механики 1С завязаны именно на свойство формы.
Поэтому, если вы измените данные в реквизите Объект программно, но не установите ЭтаФорма.Модифицированность = Истина (или не используете свойство команды), система будет считать, что с точки зрения взаимодействия с пользователем изменений не произошло, даже если данные в коллекции Объект.ТабличнаяЧасть фактически поменялись.
Подводя итог, можно выделить следующее:
ЭтаФорма.Модифицированность = Истина в клиентском коде после выполнения изменений.Следуя этим простым правилам, вы обеспечите предсказуемое поведение интерфейса и убережете пользователей от случайной потери данных.