В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает необходимость динамически изменять поведение элементов формы. Мы привыкли использовать метод УстановитьДействие для назначения программных обработчиков. Однако при работе с расширениями конфигурации программисты нередко сталкиваются с неприятной особенностью: попытка «отвязать» обработчик, передав значение Неопределено, не приводит к ожидаемому результату. Система продолжает вызывать процедуру расширения вместо стандартного системного действия или обработчика из основной конфигурации.
В этой статье мы подробно разберем, почему так происходит, проанализируем механизмы работы платформы с событиями в расширениях и рассмотрим надежные способы решения этой задачи.
Рассмотрим стандартную ситуацию. У нас есть заимствованная в расширение форма, где для поля ввода программно назначается обработчик события НачалоВыбора. Код выглядит примерно так:
Если бн_ТолькоЗаказ Тогда
Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", "БН_РасшифровкаПлатежаАналитикаРасходовНачалоВыбораВместо");
Иначе
Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", Неопределено);
КонецЕсли;
Проблема заключается в том, что когда мы передаем Неопределено, платформа пытается сбросить состояние обработчика к «значению по умолчанию», прописанному в метаданных. Однако в слоистой структуре расширений понятие «по умолчанию» становится неоднозначным:
Неопределено вернет управление именно к этому обработчику расширения, а не к логике основной конфигурации.Давайте разберем по шагам альтернативные и более надежные подходы к решению этой проблемы.
Проанализируем ситуацию: чтобы гарантированно вернуться к исходному состоянию, нам нужно точно знать, что было назначено обработчику до нашего вмешательства. Вместо того чтобы полагаться на автоматику платформы и передавать Неопределено, мы можем сохранить имя старой процедуры.
Рассмотрим пример реализации:
// В модуле формы создадим переменную для хранения старого действия
Перем ИмяСтарогоОбработчика;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Сохраняем то, что было назначено изначально (в основной конфигурации или статически)
ИмяСтарогоОбработчика = Элементы.РасшифровкаПлатежаАналитикаРасходов.ПолучитьДействие("НачалоВыбора");
КонецПроцедуры
&НаКлиенте
Процедура УправлениеОбработчиком()
Если НужноИспользоватьСвойОбработчик Тогда
Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", "МойСобственныйОбработчик");
Иначе
// Возвращаем именно то имя, которое получили через ПолучитьДействие
Элементы.РасшифровкаПлатежаАналитикаРасходов.УстановитьДействие("НачалоВыбора", ИмяСтарогоОбработчика);
КонецЕсли;
КонецПроцедуры
Этот метод является наиболее безопасным, так как он принудительно записывает в таблицу событий конкретную строку (имя процедуры). Если исходно обработчик не был назначен, ПолучитьДействие вернет пустую строку, и повторная установка пустой строки зачастую работает корректнее, чем передача Неопределено.
Выясним причину, по которой постоянная перепривязка обработчиков считается «тяжелой» операцией. Каждый вызов УстановитьДействие заставляет платформу перестраивать связи интерфейсных элементов с программным кодом. Вместо этого гораздо эффективнее назначить обработчик один раз и управлять логикой внутри него.
Посмотрим на пример кода, который позволяет избежать динамической отвязки:
&НаКлиенте
Процедура БН_РасшифровкаПлатежаАналитикаРасходовНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Проверяем условие, при котором нам НЕ нужно выполнять свой код
Если НЕ бн_ТолькоЗаказ Тогда
// Просто выходим, не меняя СтандартнаяОбработка (по умолчанию она Истина)
Возврат;
КонецЕсли;
// Если условие выполнено, реализуем свою логику
СтандартнаяОбработка = Ложь; // Отключаем системный механизм
// Ваш код кастомного выбора здесь...
ОткрытьФорму("Справочник.Заказы.ФормаВыбора", , Элемент);
КонецПроцедуры
Преимущества данного подхода:
Если специфика задачи требует именно расширения, проанализируем вариант использования аннотаций. Иногда вместо программного назначения через УстановитьДействие в модуле формы расширения, лучше использовать механизм &Вместо для системных процедур или процедур основной конфигурации.
Однако, если вы все же решили использовать программное назначение в расширении, убедитесь, что вы не дублируете обработчики. Часто ошибка возникает, когда в расширении у элемента формы уже стоит галочка события в палитре свойств, и одновременно с этим в коде вызывается УстановитьДействие. В таком случае платформа может игнорировать попытки очистки программного действия, так как статическое действие в слое расширения имеет приоритет.
Важно помнить, что если поле ввода находится внутри Таблицы формы (как в примере с расшифровкой платежа), события могут определяться на двух уровнях:
Если вы отвязываете обработчик у элемента, но он продолжает срабатывать, проверьте, не назначен ли аналогичный обработчик на уровне всей таблицы или ее колонок в основной конфигурации. В расширениях эти связи могут наследоваться сложным образом.
Проанализировав проблему, мы можем сделать следующие выводы:
УстановитьДействие("...", Неопределено) нестабилен в расширениях, если в основной конфигурации уже есть назначенные события.СтандартнаяОбработка = Ложь/Истина для управления системным поведением.ПолучитьДействие() перед внесением изменений.Применяя эти методы, мы обеспечиваем стабильную работу интерфейса и избегаем трудноуловимых багов, связанных с обновлением платформенного кэша событий.