Как программно вызвать обработчики «ПриИзменении» при заполнении табличной части документа?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке внешних обработок заполнения часто возникает ситуация, когда нам необходимо загрузить данные в табличную часть существующего документа (например, Заказ клиента). Однако простое добавление строк в программном коде не инициирует выполнение логики, которая прописана в форме документа в процедурах типа ТоварыНоменклатураПриИзменении или ТоварыЦенаПриИзменении. Платформа 1С:Предприятие разделяет интерактивные действия пользователя и программное изменение данных. Рассмотрим детально, как решить эту задачу, сохранив целостность данных и не дублируя код.

Почему обработчики не срабатывают автоматически?

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

Решение 1: Рефакторинг и вынос логики в модули (Рекомендуемый способ)

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

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


// В модуле объекта Документ.ЗаказКлиента
Процедура РассчитатьПараметрыСтрокиТЧ(СтрокаТЧ) Экспорт
    // Здесь размещается вся логика пересчета суммы, НДС и т.д.
    СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
    // ... остальная логика
КонецПроцедуры

Шаг 2. Вызов из формы. Теперь в обработчике формы мы просто вызываем этот метод объекта:


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

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

Решение 2: Использование экспортных процедур формы

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

  1. В модуле формы документа установите ключевое слово Экспорт для нужных обработчиков.
  2. В вашей обработке получите форму документа через ПолучитьФорму().
  3. Вызовите процедуру формы напрямую.

Важно: Этот метод работает только на клиенте, что накладывает серьезные ограничения на производительность при больших объемах данных.

Решение 3: Использование механизмов БСП (Библиотека стандартных подсистем)

В современных конфигурациях, таких как УТ 11, ERP или КА, большинство расчетов в табличных частях уже вынесено в специализированные общие модули. Вместо того чтобы пытаться вызвать события формы, проанализируем, какие процедуры БСП вызываются внутри формы. Часто это модули типа ОбработкаТабличныхЧастейКлиентСервер. Использование готовых функций БСП для расчета цен и сумм — это самый современный подход, который гарантирует корректность учета во всей системе.

Решение 4: Эмуляция интерактивного ввода (Трюк с ОповеститьОВыборе)

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

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


&НаКлиенте
Процедура ЗаполнитьСЭмуляцией(ФормаВладелец)
    Товары = ФормаВладелец.Объект.Товары;
    
    // Добавляем строку через элементы формы
    ФормаВладелец.Элементы.Товары.ДобавитьСтроку();
    НоваяСтрока = Товары[Товары.Количество() - 1];
    
    // Эмулируем изменение цены
    НоваяСтрока.Цена = 1500;
    ФормаВладелец.ТекущийЭлемент = ФормаВладелец.Элементы.ТоварыЦена;
    
    // Этот вызов может спровоцировать срабатывание обработчиков выбора и изменения
    ФормаВладелец.ОповеститьОВыборе(НоваяСтрока.Цена);
    
    ФормаВладелец.Элементы.Товары.ЗакончитьРедактированиеСтроки(Ложь);
КонецПроцедуры

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

Решение 5: Работа через «ДанныеФормыВЗначение» на сервере

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

Разберем алгоритм:

  1. Передаем Объект (данные формы) на сервер.
  2. Преобразуем его в реальный объект: ДокОбъект = ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект.ЗаказКлиента"));.
  3. Программно заполняем таблицу в ДокОбъект.
  4. Вызываем методы объекта для пересчета.
  5. Загружаем данные обратно: ЗначениеВДанныеФормы(ДокОбъект, Объект);.

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

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

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

Для решения вашей задачи мы рекомендуем:

Такой подход сделает ваш код надежным, легко тестируемым и соответствующим стандартам разработки 1С.

← На главную