Почему процедура в расширении 1С выполняется дважды или возвращается в начало?

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

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

Суть проблемы: двойной вызов при открытии форм

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

Пример кода, который может вызывать подобное поведение:


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

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

Диагностика с помощью стека вызовов

Первым делом нам необходимо понять, кто именно инициирует повторный вызов. Для этого в 1С существует мощный инструмент — Стек вызовов. Разберем по шагам, как его использовать для локализации проблемы:

  1. Установите точку останова в самом начале процедуры, которая выполняется дважды.
  2. Запустите отладку и дождитесь остановки программы.
  3. Когда выполнение прервется на точке останова, нажмите сочетание клавиш Ctrl + Alt + C (или выберите в меню «Отладка» — «Стек вызовов»).
  4. Внимательно изучите список процедур. Если вы видите, что ваша процедура Вложения_ПрикрепитьФайлПосле встречается в списке несколько раз или вызывается из неожиданных мест (например, из системных обработчиков событий), значит, мы имеем дело с дублированием событий.

Проанализируем пример реального стека вызовов из подобной ситуации:


Документ.Расш2_Дело.Форма.ФормаДокумента.Форма.Вложения_ПрикрепитьФайлПосле(Команда = КомандаФормы)
Справочник.ПрикрепленныеФайлы.Форма.ФормаЭлемента.Форма.ПриОткрытии(Отказ = Ложь)
Документ.Расш2_Дело.Форма.ФормаДокумента.Форма.Вложения_ПрикрепитьФайлПосле(Команда = КомандаФормы)

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

Причина №1: Копирование команд и конфликты GUID

Как показывает практика, наиболее частая причина «самопроизвольного» перехода на начало процедуры — это копирование объектов метаданных в расширении. Рассмотрим, что происходит «под капотом»:

Когда вы копируете команду из другого расширения или из основной конфигурации, платформа может перенести вместе с ней внутренние идентификаторы (GUID). Если в расширении оказывается две кнопки или две команды, которые платформа считает идентичными из-за конфликта идентификаторов, она может попытаться выполнить действие для каждой из них. Или, что еще хуже, событие нажатия кнопки связывается одновременно и с обработчиком команды, и с обработчиком события кнопки.

Решение проблемы:

Никогда не используйте копирование (Ctrl+C / Ctrl+V) для создания команд в расширениях, если они должны управлять логикой формы. Вместо этого:

  1. Создайте новую команду в дереве объектов расширения вручную.
  2. Дайте ей уникальное имя.
  3. Перейдите в свойства кнопки на форме и в поле ИмяКоманды выберите только что созданную команду.
  4. Создайте новый обработчик события для этой команды.

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

Причина №2: Использование аннотации &После (&After)

Разберем особенности работы расширений. Когда мы используем аннотацию &После, платформа выполняет сначала основной код процедуры из конфигурации поставщика, а затем — наш код из расширения.

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

Причина №3: Двойная привязка обработчика

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

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

Дополнительные методы отладки

Если пересоздание команды не помогло, рассмотрим дополнительные методы диагностики:

1. Замер производительности

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

2. Проверка фокуса и синхронных вызовов

Иногда «прыжки» связаны с модальностью или синхронными вызовами. Хотя ОткрытьФорму является асинхронным методом, в некоторых режимах работы (особенно в веб-клиенте или при блокировке всего интерфейса) платформа может некорректно восстанавливать контекст после открытия окна.

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


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

&НаКлиенте
Процедура ПослеЗакрытияФормыВложений(Результат, ДополнительныеПараметры) Экспорт
    // Код, который должен выполниться после закрытия формы
КонецПроцедуры

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

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

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

← На главную