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