Как программно отвязать обработчик события от поля ввода в 1С

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

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

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

Почему стандартный метод УстановитьДействие("...", Неопределено) может давать сбой?

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


Если бн_ТолькоЗаказ Тогда
    Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", "БН_РасшифровкаПлатежаАналитикаРасходовНачалоВыбораВместо");
Иначе
    Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", Неопределено);
КонецЕсли;

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

  1. Конфликт слоев метаданных: Если в основной конфигурации обработчик уже был назначен статически, а в расширении вы программно назначили свой, то при попытке очистки платформа может «зависнуть» на последнем успешно установленном значении из-за особенностей кэширования таблицы событий.
  2. Особенности релизов платформы: В ряде версий 1С (особенно в ветках 8.3.15–8.3.18) зафиксированы случаи, когда динамическое изменение обработчика для элементов, находящихся внутри таблиц формы, не обновляет внутренний указатель события немедленно.
  3. Статическое назначение в расширении: Если обработчик был указан в редакторе формы расширения (даже если поле заимствовано), то программная установка Неопределено вернет управление именно к этому обработчику расширения, а не к логике основной конфигурации.

Давайте разберем по шагам альтернативные и более надежные подходы к решению этой проблемы.

Способ №1: Метод сохранения и восстановления исходного действия (Backup)

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

Рассмотрим пример реализации:


// В модуле формы создадим переменную для хранения старого действия
Перем ИмяСтарогоОбработчика;

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Сохраняем то, что было назначено изначально (в основной конфигурации или статически)
    ИмяСтарогоОбработчика = Элементы.РасшифровкаПлатежаАналитикаРасходов.ПолучитьДействие("НачалоВыбора");
КонецПроцедуры

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

Этот метод является наиболее безопасным, так как он принудительно записывает в таблицу событий конкретную строку (имя процедуры). Если исходно обработчик не был назначен, ПолучитьДействие вернет пустую строку, и повторная установка пустой строки зачастую работает корректнее, чем передача Неопределено.

Способ №2: Использование флага СтандартнаяОбработка (Рекомендуемый)

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

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


&НаКлиенте
Процедура БН_РасшифровкаПлатежаАналитикаРасходовНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    // Проверяем условие, при котором нам НЕ нужно выполнять свой код
    Если НЕ бн_ТолькоЗаказ Тогда
        // Просто выходим, не меняя СтандартнаяОбработка (по умолчанию она Истина)
        Возврат;
    КонецЕсли;

    // Если условие выполнено, реализуем свою логику
    СтандартнаяОбработка = Ложь; // Отключаем системный механизм
    
    // Ваш код кастомного выбора здесь...
    ОткрытьФорму("Справочник.Заказы.ФормаВыбора", , Элемент);
    
КонецПроцедуры

Преимущества данного подхода:

Способ №3: Динамическое подключение через расширение

Если специфика задачи требует именно расширения, проанализируем вариант использования аннотаций. Иногда вместо программного назначения через УстановитьДействие в модуле формы расширения, лучше использовать механизм &Вместо для системных процедур или процедур основной конфигурации.

Однако, если вы все же решили использовать программное назначение в расширении, убедитесь, что вы не дублируете обработчики. Часто ошибка возникает, когда в расширении у элемента формы уже стоит галочка события в палитре свойств, и одновременно с этим в коде вызывается УстановитьДействие. В таком случае платформа может игнорировать попытки очистки программного действия, так как статическое действие в слое расширения имеет приоритет.

Нюансы работы с таблицами формы

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

  1. У самого Элемента (Поля ввода).
  2. У Колонки таблицы.

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

Резюме и рекомендации

Проанализировав проблему, мы можем сделать следующие выводы:

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

← На главную