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