Как открыть несколько управляемых форм в цикле и установить признак модифицированности в 1С?

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

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

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

Часть 1. Разбираемся с уникальностью форм в цикле

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

Типичный ошибочный код выглядит следующим образом:


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

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

Все дело в четвертом параметре метода ОткрытьФорму, который называется Уникальность. Давайте проанализировать, как платформа интерпретирует этот параметр:

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

Рекомендация: Хотя передача значения Истина решает проблему «в лоб», хорошим стилем программирования в 1С является генерация и передача нового уникального идентификатора. Это позволит вам при необходимости в дальнейшем программно взаимодействовать именно с конкретным окном. Исправленный код будет выглядеть так:


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

С уникальностью окон мы разобрались. Теперь перейдем ко второй важной проблеме — установке «звездочки» модифицированности.

Часть 2. Почему не появляется признак модифицированности при программном открытии?

Когда пользователь интерактивно вводит данные на форме (например, пишет текст в поле ввода), платформа 1С автоматически устанавливает свойство формы Модифицированность в значение Истина. В заголовке окна появляется символ *, и при попытке закрыть окно система спросит пользователя: "Данные были изменены. Сохранить изменения?".

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

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

Рассмотрим три надежных сценария решения этой проблемы.

Вариант А. Разделение процесса на получение формы и ее открытие

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

Вместо моментального вызова ОткрытьФорму мы сначала получаем объект формы в переменную с помощью функции ПолучитьФорму, затем непосредственно на клиенте взводим свойство Модифицированность, и только после этого открываем форму.

Посмотрим на пример реализации:


&НаКлиенте
Процедура ОткрытьФормыСМодификацией()
    Для Каждого Строка Из СписокДоговоров Цикл
        ПараметрыФормы = Новый Структура("Основание", Строка.Договор);
        УникальныйКлюч = Новый УникальныйИдентификатор();
        
        // Шаг 1. Получаем форму без ее отображения
        НоваяФорма = ПолучитьФорму("Справочник.Договоры.Форма.ФормаЭлемента", 
                                   ПараметрыФормы, 
                                   ЭтотОбъект, 
                                   УникальныйКлюч);
        
        // Шаг 2. Устанавливаем модифицированность на клиенте
        НоваяФорма.Модифицированность = Истина;
        
        // Шаг 3. Отображаем форму пользователю
        НоваяФорма.Открыть();
    КонецЦикла;
КонецПроцедуры

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

Вариант Б. Установка модифицированности в клиентском событии «ПриОткрытии»

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

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


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Проверяем, что это новый объект, который мы создаем программно
    Если Не ЗначениеЗаполнено(Объект.Ссылка) Тогда
        ЭтаФорма.Модифицированность = Истина;
    КонецЕсли;
КонецПроцедуры

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

Вариант В. Использование стандартного механизма «ЗначениеЗаполнения»

В платформе 1С:Предприятие 8 реализован мощный встроенный механизм заполнения новых объектов. Если ваша цель — создать новый элемент и заполнить его реквизиты на основании каких-либо данных, рекомендуется использовать предопределенный параметр ЗначениеЗаполнения вместо передачи произвольных параметров.

Проанализируем этот подход по шагам:

  1. В вызывающем коде мы подготавливаем структуру заполнения. Имя ключа в структуре должно строго совпадать с именем реквизита создаваемого объекта (например, реквизит ДоговорОснование в справочнике).
  2. Передаем эту структуру в параметрах открытия формы под ключом ЗначениеЗаполнения.
  3. Платформа 1С при создании объекта автоматически вызывает стандартную процедуру ОбработкаЗаполнения в модуле объекта и самостоятельно взводит флаг модифицированности формы, так как данные объекта были изменены в рамках стандартного бизнес-процесса.

Пример вызова на клиенте:


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

Этот способ считается самым правильным с точки зрения стандартов разработки фирмы «1С», поскольку он задействует штатные механизмы платформы, минимизирует написание ручного кода в формах и автоматически обеспечивает правильное поведение интерфейса.

Резюме

Мы подробно изучили механизмы работы с формами в цикле. Для успешного решения подобных задач всегда помните два золотых правила:

← На главную