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

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

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

Почему стандартные методы не работают?

Разберем причину возникновения проблемы. В управляемых формах существует четкое разделение на данные формы (структура Объект) и элементы формы (визуальное представление). Когда пользователь вручную выбирает значение в таблице, платформа выполняет целый каскад действий: позиционируется на строке, устанавливает фокус на элементе и только потом запускает событие ПриИзменении. При программном добавлении строки через Объект.ТабЧасть.Добавить() мы меняем данные, но элемент формы (визуальная таблица) об этом «не знает» в контексте текущего фокуса. Свойство ТекущиеДанные остается неопределенным, так как активная строка в интерфейсе не была выбрана.

Способ 1. Программное позиционирование на строке

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

Важно помнить, что в управляемом приложении свойство ТекущаяСтрока принимает не саму строку и не её индекс, а внутренний идентификатор. Рассмотрим пошаговый алгоритм:

  1. Добавляем строку в данные формы.
  2. Получаем идентификатор созданной строки с помощью метода ПолучитьИдентификатор().
  3. Устанавливаем этот идентификатор в свойство ТекущаяСтрока элемента формы.
  4. Вызываем процедуру-обработчик.

Пример реализации на клиенте:


// Добавляем новую строку в данные объекта формы
НоваяСтрокаДанных = Объект.Товары.Добавить();
НоваяСтрокаДанных.Номенклатура = ВыбраннаяНоменклатура;

// Чтобы ТекущиеДанные заполнились, нужно позиционировать элемент формы
ИдентификаторСтроки = НоваяСтрокаДанных.ПолучитьИдентификатор();
Элементы.Товары.ТекущаяСтрока = ИдентификаторСтроки;

// Теперь ТекущиеДанные будут указывать на нашу новую строку
// Можем вызвать экспортный обработчик события
ТоварыНоменклатураПриИзменении(Элементы.ТоварыНоменклатура);

Обратите внимание: обработчик события (например, ТоварыНоменклатураПриИзменении) должен иметь ключевое слово Экспорт в модуле формы, иначе вызвать его извне (например, из внешней обработки) не получится.

Способ 2. Вынос логики в модули (Best Practice)

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

Рекомендуемый подход:

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

Посмотрим на пример кода в модуле объекта:


Процедура ЗаполнитьРеквизитыНоменклатуры(СтрокаТаблицы) Экспорт
    СтрокаТаблицы.ЕдиницаИзмерения = СтрокаТаблицы.Номенклатура.ЕдиницаХранения;
    СтрокаТаблицы.Коэффициент = 1;
    // Здесь может быть вызов сервера для получения цен
КонецПроцедуры

Теперь в модуле формы наш обработчик будет выглядеть крайне лаконично:


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

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

Способ 3. Передача элемента формы в качестве параметра

Если нам все же необходимо вызвать именно процедуру формы (например, конфигурация типовая и мы не можем менять модуль объекта), выясним, как правильно передать параметры. Большинство обработчиков событий принимают один аргумент — Элемент. Это объект типа ПолеФормы.

Если внутри обработчика код обращается к свойствам этого элемента (например, Элемент.Имя), то простая передача значения Неопределено вызовет ошибку. Выясним, как передать правильный объект:


// Получаем форму документа (если работаем из внешней обработки)
ФормаДокумента = ПолучитьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента");

// ... заполнение данных ...

// Вызываем обработчик, передавая ему фактический элемент формы
ФормаДокумента.ТоварыНоменклатураПриИзменении(ФормаДокумента.Элементы.ТоварыНоменклатура);

Важный нюанс: Этот метод сработает только в том случае, если процедура помечена как &НаКлиенте и является Экспортной.

Типичные ошибки и их решение

Рассмотрим основные грабли, на которые наступают разработчики:

Итоги

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

← На главную