При разработке сложных управляемых форм часто возникает задача создания зависимых списков. Типичный сценарий: на форме расположены две независимые таблицы (динамические списки), а третья таблица должна отображать данные, зависящие от того, какая именно из первых двух таблиц в текущий момент выбрана пользователем и какая строка в ней активна.
Однако разработчики сталкиваются с проблемой: стандартные события таблиц ПриАктивизацииСтроки и ПриАктивизацииЯчейки срабатывают только при физическом перемещении курсора по строкам внутри конкретной таблицы. Если пользователь щелкает мышью по уже выделенной строке соседней таблицы, платформа не инициирует эти события, так как индекс текущей строки не изменился. Рассмотрим особенности платформы и разберем варианты решения данной задачи.
Проанализируем поведение платформы «1С:Предприятие 8» при работе с элементами управляемой формы:
OnFocus или OnBlur. Платформа регистрирует действия с данными, а не сам факт установки фокуса ввода на элемент.ПриАктивизацииСтроки и ПриАктивизацииЯчейки вызываются только при смене координат курсора относительно предыдущего состояния внутри одной и той же таблицы. Клик по уже активной строке игнорируется платформой для снижения нагрузки.Выбор срабатывает исключительно по двойному клику или нажатию клавиши Enter. Событие Нажатие доступно для кнопок, флажков или колонок с режимом гиперссылки, но не отслеживает одиночные нажатия на стандартные текстовые ячейки списка в режиме просмотра.Если интерфейс требует одновременного присутствия обеих таблиц на экране, наиболее гибким решением является периодический опрос активного элемента формы с помощью метода ПодключитьОбработчикОжидания. Разберем по шагам, как реализовать этот механизм без создания лишней нагрузки на сервер.
В модуле формы объявим клиентскую переменную для хранения имени последней активной таблицы, а также настроим подключение и отключение обработчика:
&НаКлиенте
Перем ПредыдущаяТаблица;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПредыдущаяТаблица = "";
ПодключитьОбработчикОжидания("ПроверитьСменуАктивнойТаблицы", 0.2, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
ОтключитьОбработчикОжидания("ПроверитьСменуАктивнойТаблицы");
КонецПроцедуры
Теперь создадим процедуру проверки. Обратите внимание: фокус ввода может находиться как на самой таблице, так и на конкретном поле ввода внутри неё. Поэтому проверяем как сам ЭтаФорма.ТекущийЭлемент, так и его родительский элемент:
&НаКлиенте
Процедура ПроверитьСменуАктивнойТаблицы()
ТекущийЭлементФормы = ЭтаФорма.ТекущийЭлемент;
Если ТекущийЭлементФормы = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущееИмяТаблицы = "";
// Проверяем принадлежность элемента первой таблице
Если ТекущийЭлементФормы = Элементы.ТаблицаСписок1 ИЛИ ТекущийЭлементФормы.Родитель = Элементы.ТаблицаСписок1 Тогда
ТекущееИмяТаблицы = "ТаблицаСписок1";
// Проверяем принадлежность элемента второй таблице
ИначеЕсли ТекущийЭлементФормы = Элементы.ТаблицаСписок2 ИЛИ ТекущийЭлементФормы.Родитель = Элементы.ТаблицаСписок2 Тогда
ТекущееИмяТаблицы = "ТаблицаСписок2";
КонецЕсли;
// Если фокус перешел на одну из таблиц и это новая таблица — обновляем зависимый список
Если Не ПустаяСтрока(ТекущееИмяТаблицы) И ТекущееИмяТаблицы <> ПредыдущаяТаблица Тогда
ПредыдущаяТаблица = ТекущееИмяТаблицы;
ОбновитьЗависимыйСписок(ТекущееИмяТаблицы);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьЗависимыйСписок(ИмяАктивнойТаблицы)
// Логика установки параметров или отборов для третьего динамического списка
Если ИмяАктивнойТаблицы = "ТаблицаСписок1" Тогда
ТекущиеДанные = Элементы.ТаблицаСписок1.ТекущиеДанные;
Иначе
ТекущиеДанные = Элементы.ТаблицаСписок2.ТекущиеДанные;
КонецЕсли;
// Вызов серверной процедуры пересчета параметров списка 3
ОбновитьСписок3НаСервере(ТекущиеДанные);
КонецПроцедуры
Если бизнес-логика позволяет разнести списки по вкладкам, это полностью устраняет проблему фокуса. Выясним преимущества такого подхода:
ПриСменеСтраницы.
&НаКлиенте
Процедура ГруппаСтраницыПриСменеСтраницы(Элемент, ТекущаяСтраница)
Если ТекущаяСтраница = Элементы.СтраницаПервыйСписок Тогда
ТекущиеДанные = Элементы.ТаблицаСписок1.ТекущиеДанные;
Иначе
ТекущиеДанные = Элементы.ТаблицаСписок2.ТекущиеДанные;
КонецЕсли;
ОбновитьСписок3НаСервере(ТекущиеДанные);
КонецПроцедуры
Если интерфейс не должен перегружаться обработчиками ожидания, можно предоставить пользователю явный элемент взаимодействия:
Гиперссылка = Истина.Нажатие.Рассмотрим еще один архитектурный вариант: объединение данных первого и второго списков в единый источник с помощью запроса динамического списка (оператор ОБЪЕДИНИТЬ ВСЕ). Разделение сущностей можно выполнить с помощью группировок, иерархии или дополнительной колонки-признака. В этом случае пользователь перемещается исключительно внутри одной таблицы, и событие ПриАктивизацииСтроки гарантированно отрабатывает при каждом выборе.