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