Как программно вызвать обработчик «ПриИзменении» в управляемой форме 1С, если функция не экспортная

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

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

Почему прямой вызов не работает?

В управляемых формах (УФ) реализована строгая инкапсуляция. Модуль формы является контекстом, доступ к которому извне крайне ограничен. Если процедура ИмяРеквизитаПриИзменении не объявлена как экспортная, вы не сможете вызвать её через точку от объекта формы, полученного функцией ПолучитьФорму(). Попытка выполнить код НужнаяФорма.КонтрагентПриИзменении() приведет к ошибке выполнения, так как метод не обнаружен.

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

Способ 1. Использование расширений конфигурации (рекомендуемый)

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

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

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


&НаКлиенте
Процедура Расш1_ВызватьПриИзмененииКонтрагента() Экспорт
    // Вызываем оригинальную неэкспортную процедуру
    КонтрагентПриИзменении(Элементы.Контрагент);
КонецПроцедуры

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


ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДок = ПолучитьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);
ФормаДок.Открыть();
// Теперь вызываем нашу экспортную процедуру из расширения
ФормаДок.Расш1_ВызватьПриИзмененииКонтрагента();

Способ 2. Эмуляция выбора через «ОповеститьОВыборе»

Этот метод основан на особенностях работы платформы с параметром Владелец при открытии форм. Когда форма открывается с указанием владельца (конкретного элемента управления другой формы), вызов метода ОповеститьОВыборе автоматически инициирует событие ОбработкаВыбора у владельца, что в большинстве случаев влечет за собой и вызов ПриИзменении.

Выясним, как реализовать этот механизм по шагам:

  1. Определяем целевой элемент управления на форме документа (например, Элементы.Контрагент).
  2. Открываем вспомогательную форму (это может быть форма выбора или даже пустая форма вашей обработки), передав в качестве владельца этот элемент.
  3. В открытой вспомогательной форме вызываем ОповеститьОВыборе(НужноеЗначение).

Пример кода для реализации этого подхода:


// В контексте вызывающей формы или обработки
ПараметрыОткрытия = Новый Структура;
// Передаем элемент управления целевой формы как владельца
СтруктураПараметров = Новый Структура("Владелец", ЦелеваяФорма.Элементы.Контрагент);
// Открываем форму выбора, которая вернет значение
ОткрытьФорму("Справочник.Контрагенты.ФормаВыбора", ПараметрыОткрытия, ЦелеваяФорма.Элементы.Контрагент);

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

Способ 3. Использование механизма «ПараметрыЗаполнения»

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

Если логика заполнения вынесена в модуль объекта (что является правилом хорошего тона), мы можем передать данные при открытии:


ЗначенияЗаполнения = Новый Структура;
ЗначенияЗаполнения.Вставить("Контрагент", СсылкаНаКонтрагента);
ЗначенияЗаполнения.Вставить("Договор", СсылкаНаДоговор);

ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ЗначенияЗаполнения", ЗначенияЗаполнения);

ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыФормы);

Важное ограничение: Этот метод сработает только для новых объектов и только если логика пересчета реализована в процедуре ОбработкаЗаполнения модуля объекта. Если же алгоритмы прописаны только в модуле формы в процедуре ПриИзменении, этот способ не поможет.

Способ 4. Оповещение и «ОбработкаОповещения»

Проанализируем ситуацию, когда форма документа уже открыта, и нам нужно заставить её среагировать на изменение данных. Многие типовые конфигурации (особенно построенные на базе БСП) используют механизм оповещений.

Если в целевой форме есть процедура ОбработкаОповещения, мы можем отправить глобальное оповещение:

Оповестить("ОбновитьДанныеКонтрагента", СсылкаНаКонтрагента, ЭтаФорма);

В модуле целевой формы код может выглядеть так:


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

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

Способ 5. Менеджер тестирования

Для полноты картины упомянем способ, который обычно используется для автотестов, но технически позволяет «нажимать кнопки» и «менять поля» программно. Используя ТестируемоеПриложение, можно найти окно формы, найти в нем элемент и вызвать метод ИзменитьТекст().

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

Подведем итоги

Выбор метода зависит от ваших возможностей по модификации системы:

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

← На главную