Почему в расширении 1С у табличной части нет события ПриАктивизацииСтроки и как это исправить?

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

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

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

Выясняем причину: почему платформа «скрывает» события?

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

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

Рассмотрим детально три способа решения этой задачи.

Способ 1. Заимствование ключевого реквизита формы (классический путь)

Самый очевидный способ, который предлагает сама среда разработки, — это перенос основного реквизита в расширение.

Проанализируем этот процесс по шагам:

  1. Откроем редактор формы в расширении.
  2. Перейдем на вкладку Реквизиты (в правой верхней панели редактора формы).
  3. Найдем затененный реквизит Объект (или иной реквизит, являющийся источником данных для нашей таблицы).
  4. Вызовем контекстное меню правой кнопкой мыши и выберем команду Добавить в расширение.

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

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

Способ 2. Визуальный трюк без заимствования реквизитов и написания кода

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

  1. Откроем форму в расширении и перейдем в дерево элементов формы (левая панель).
  2. Вместо перетаскивания таблицы из реквизитов, нажмем клавишу Insert (или кнопку Добавить) непосредственно в дереве элементов.
  3. В появившемся окне выбора типа элемента укажем тип — Таблица.
  4. Перейдем в свойства созданной таблицы и в поле ПутьКДанным вручную впишем путь к нашей табличной части (например, Объект.Товары).
  5. Платформа распознает структуру данных и выведет диалоговое окно с вопросом: «Создать колонки таблицы формы?». Соглашаемся и нажимаем Да.

Этот простой обходной путь заставляет платформу корректно сопоставить типы. Нам становятся доступны все команды таблицы и полный список интерактивных событий в палитре свойств, включая ПриАктивизацииСтроки, при этом сам реквизит Объект заимствовать в расширение не требуется!

Способ 3. Программная привязка обработчика через УстановитьДействие()

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

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


&НаКлиенте
Процедура Расш_ОтобразитьОстаток(Элемент)
    Если Элемент.ТекущиеДанные <> Неопределено Тогда
        // Здесь будет выполняться логика при активации строки
        ОтобразитьОстатокНаКлиенте(Элемент.ТекущиеДанные.Номенклатура);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура Расш_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    ТаблицаТоваров = Элементы.Товары;
    ТаблицаТоваров.УстановитьДействие("ПриАктивизацииСтроки", "Расш_ОтобразитьОстаток");
КонецПроцедуры

Разберем особенности работы метода УстановитьДействие() в управляемых формах:

Критическая угроза производительности: как не «повесить» систему

Очень часто начинающие разработчики совершают грубейшую ошибку при написании кода в обработчике ПриАктивизацииСтроки. Рассмотрим типичный пример неудачного кода:


// ОПАСНЫЙ КОД! ТАК ДЕЛАТЬ НЕЛЬЗЯ!
&НаКлиенте
Процедура Расш_ОтобразитьОстаток(Элемент)
    Если Элемент.ТекущиеДанные <> Неопределено Тогда
        // Прямой вызов контекстного серверного метода формы
        Элементы.ТекущийОстаток.Заголовок = ПолучитьОстатокНаСервере(Элемент.ТекущиеДанные.Номенклатура);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Функция ПолучитьОстатокНаСервере(Номенклатура)
    Возврат РегистрыНакопления.ТоварыНаСкладах.Остаток(Номенклатура);
КонецФункции

Почему этот код опасен и может привести к зависанию интерфейса или аварийному завершению сеанса («вылету» программы)?

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

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

Оптимальное решение: использование обработчика ожидания

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

Проанализируем правильный шаблон реализации:


&НаКлиенте
Процедура Расш_ОтобразитьОстаток(Элемент)
    // 1. Каждый раз при переходе на новую строку отключаем старый таймер
    ОтключитьОбработчикОжидания("Подключаемый_ОтобразитьОстаток");
    
    // 2. Запускаем легкую задержку в 0.1 - 0.2 секунды.
    // Вызов произойдет однократно, когда пользователь перестанет листать список
    ПодключитьОбработчикОжидания("Подключаемый_ОтобразитьОстаток", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ОтобразитьОстаток()
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // 3. Вызываем сервер строго БЕЗ контекста формы для максимального быстродействия
        Остаток = ПолучитьОстатокНоменклатурыБезКонтекста(ТекущиеДанные.Номенклатура);
        Элементы.ТекущийОстаток.Заголовок = Строка(Остаток);
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьОстатокНоменклатурыБезКонтекста(Номенклатура)
    // Оптимальный запрос к базе данных без передачи контекста формы
    Возврат Справочники.Номенклатура.ПолучитьОстаток(Номенклатура); 
КонецФункции

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

← На главную