Как проверить, открыта форма документа или нет в 1С (обычные формы)

Программист 1С v8.3 (Обычные формы)
← На главную

В процессе разработки в среде 1С:Предприятие (особенно в конфигурациях на обычных формах, таких как УПП или КА 1.1) программисты часто сталкиваются с задачей: при определенных действиях с документом нужно автоматически открыть другой документ, созданный на его основании. При этом важно избежать «замусоривания» интерфейса — если форма документа-основания уже открыта, программа должна не создавать новую, а просто активизировать существующую. Рассмотрим, почему стандартные методы могут не работать и как правильно реализовать этот механизм.

Анализ проблемы: почему метод Открыта() возвращает Ложь?

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

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

Во-вторых, метод Открыта() возвращает Истина только тогда, когда форма уже прошла все стадии инициализации и отображена пользователю. Если вы только что получили форму методом ПолучитьФорму(), она еще находится в состоянии «создана», но не «открыта».

Главная архитектурная ошибка: интерактивность в транзакции

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

  1. Блокировки: Пока форма открыта и пользователь на нее смотрит, транзакция проведения остается незавершенной. Это блокирует таблицы базы данных для всех остальных пользователей.
  2. Отказ от транзакции: Если после открытия формы проведение документа сорвется (например, из-за нехватки остатков), форма созданного документа останется висеть в интерфейсе, хотя логически процесс не завершен.
  3. Клиент-серверное разделение: В современных версиях платформы серверный код (модуль объекта) в принципе не имеет доступа к методам открытия форм.

Вывод: Логику открытия форм необходимо выносить из модуля объекта в модуль формы (на сторону клиента).

Решение 1: Правильное использование Ключа Уникальности

Для того чтобы система сама находила уже открытую форму, мы должны использовать параметр КлючУникальности в методе ПолучитьФорму(). Рассмотрим, как реализовать это в модуле формы основного документа, например, в процедуре ПослеЗаписи или при нажатии на специальную кнопку.

Разберем пример кода для обычного приложения:


Процедура ПослеЗаписи()
    // Проверяем условие, нужно ли создавать связанный документ
    Если СодержимоеДМ Тогда
        // В качестве ключа уникальности лучше использовать ссылку на текущий документ
        // Это гарантирует, что для этого документа-основания будет только одна форма ДМ
        КлючУникальности = "ДвижениеДМ_" + Строка(ЭтотОбъект.Ссылка.УникальныйИдентификатор());
        
        // Пытаемся получить форму. Если она уже открыта, система вернет ссылку на нее
        ФормаДМ = Документы.ДвижениеДрагоценныхМатериалов.ПолучитьФорму("ФормаДокумента", , КлючУникальности);
        
        Если НЕ ФормаДМ.Открыта() Тогда
            // Если форма не открыта, значит документ еще не создавался в этом сеансе
            НовыйДок = Документы.ДвижениеДрагоценныхМатериалов.СоздатьДокумент();
            НовыйДок.ДокументОснование = ЭтотОбъект.Ссылка;
            НовыйДок.Заполнить(ЭтотОбъект.Ссылка);
            
            // Копируем данные в форму
            КопироватьДанныеОбъекта(НовыйДок, ФормаДМ.ДокументОбъект);
            ФормаДМ.Открыть();
        Иначе
            // Если открыта — просто активизируем её
            ФормаДМ.Активизировать();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Решение 2: Использование механизма оповещений

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

Шаг 1. В форме основного документа после записи вызываем оповещение:

Оповестить("ПроверитьОткрытуюФормуДМ", ЭтотОбъект.Ссылка, ЭтаФорма);

Шаг 2. В форме документа "ДвижениеДрагоценныхМатериалов" создаем обработчик события ОбработкаОповещения:


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

Этот метод позволяет избежать жесткой привязки к ключам уникальности и дает возможность формам «общаться» друг с другом напрямую.

Решение 3: Проверка наличия записанного документа

Часто вопрос «открыта ли форма» подменяет собой вопрос «создан ли уже такой документ». Если ваша задача — не плодить дубликаты в базе данных, то проверять нужно не состояние интерфейса, а наличие записей в таблицах.

Выясним причину повторных открытий: если документ уже был записан ранее, нам нужно найти его ссылку и открыть именно её форму, а не создавать новый объект методом СоздатьДокумент().


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ Ссылка 
    |ИЗ Документ.ДвижениеДрагоценныхМатериалов 
    |ГДЕ ДокументОснование = &Основание";
Запрос.УстановитьПараметр("Основание", СсылкаНаОснование);
Результат = Запрос.Выполнить();

Если НЕ Результат.Пустой() Тогда
    Выборка = Результат.Выбрать();
    Выборка.Следующий();
    // Документ уже есть в базе, открываем его форму
    ФормаСуществующего = Выборка.Ссылка.ПолучитьФорму();
    ФормаСуществующего.Открыть();
Иначе
    // Документа нет, создаем новый
    // ... логика создания ...
КонецЕсли;

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

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

← На главную