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