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