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