При разработке интерфейсов в обычных формах часто возникает задача: предоставить пользователю возможность отметить произвольные строки в списке документов с помощью флажков и затем выполнить групповую обработку только для выбранных позиций. Однако попытка перебрать строки элемента управления ДокументСписок с помощью стандартного цикла Для каждого приводит к ошибке «Итератор не определен». Проанализируем, почему возникает эта ошибка и как правильно реализовать выбор и обход строк.
Выясним причину такого поведения платформы. Объект ДокументСписок не является коллекцией данных, полностью загруженной в оперативную память (в отличие от объекта ТаблицаЗначений или Массив). Это динамический считыватель данных из информационной базы, который подгружает с сервера только ту часть строк, которая в данный момент видна на экране пользователя.
Кроме того, если в табличное поле добавлена колонка «Флажок», не связанная с реквизитом документа в базе данных, эта колонка существует только на уровне визуального отображения текущих видимых строк. Сам ДокументСписок ничего не знает о состоянии таких флажков.
Разберем по шагам классический и наиболее производительный подход для работы с флажками выбора в обычных формах. Поскольку динамический список не хранит пользовательские отметки, мы будем запоминать ссылки на выбранные документы в отдельной переменной модуля формы — объекте Соответствие или Массив.
Рассмотрим реализацию механизма:
Перем мОтмеченныеДокументы;
ПриОткрытии инициализируем коллекцию:
Процедура ПриОткрытии()
мОтмеченныеДокументы = Новый Соответствие;
КонецПроцедуры
ПриВыводеСтроки (или пакетное событие ПриПолученииДанных):
Процедура ДокументСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Проверяем наличие текущей ссылки в нашей коллекции отметок
Если мОтмеченныеДокументы[ДанныеСтроки.Ссылка] = Истина Тогда
ОформлениеСтроки.Ячейки.Флажок.УстановитьФлажок(Истина);
Иначе
ОформлениеСтроки.Ячейки.Флажок.УстановитьФлажок(Ложь);
КонецЕсли;
КонецПроцедуры
ПриИзмененииФлажка или Выбор) обновляем наше соответствие:
Процедура ДокументСписокПриИзмененииФлажка(Элемент, Колонка)
Если Колонка.Имя = "Флажок" Тогда
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
СсылкаНаДокумент = ТекущиеДанные.Ссылка;
Если мОтмеченныеДокументы[СсылкаНаДокумент] = Истина Тогда
мОтмеченныеДокументы.Удалить(СсылкаНаДокумент);
Иначе
мОтмеченныеДокументы.Вставить(СсылкаНаДокумент, Истина);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ВыполнитьОбработкуОтмеченных()
Для Каждого ЭлементОтбора Из мОтмеченныеДокументы Цикл
СсылкаНаДокумент = ЭлементОтбора.Ключ;
// Выполняем требуемые действия с документом
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// ... логика обработки ...
КонецЦикла;
КонецПроцедуры
Рассмотрим ситуацию, когда требуется получить все строки списка с учетом пользовательских фильтров и отборов, настроенных в форме (например, для реализации кнопки «Отметить все» или выгрузки отфильтрованных данных).
Для этого используется объект ПостроительЗапроса. Важно помнить, что передать ДокументСписок напрямую в свойство ИсточникДанных нельзя, так как возникнет ошибка несоответствия типов. Необходимо обернуть его в объект ОписаниеИсточникаДанных.
Посмотрим на пример кода:
Процедура ПолучитьВсеСтрокиСписка()
Построитель = Новый ПостроительЗапроса;
// Передаем ДокументСписок через ОписаниеИсточникаДанных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ДокументСписок);
// Выполняем выборку с учетом всех интерактивных отборов формы
Результат = Построитель.Результат;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Доступ к реквизитам документов из текущего списка
СсылкаНаДокумент = Выборка.Ссылка;
// Например, отмечаем все документы из текущего отбора:
мОтмеченныеДокументы.Вставить(СсылкаНаДокумент, Истина);
КонецЦикла;
// Обновляем визуальное отображение строк в табличном поле
ЭлементыФормы.ДокументСписок.ОбновитьСтроки();
КонецПроцедуры
Если добавление отдельной колонки с флажками не является строгим требованием интерфейса, проанализируем штатную альтернативу — множественное выделение строк мышью и клавиатурой (Shift / Ctrl).
ЭлементыФормы.ДокументСписок.РежимВыделения = РежимВыделенияТабличногоПоля.Множественный;
ВыделенныеСтроки:
Процедура ОбработатьВыделенныеСтроки()
Для Каждого СтрокаСписка Из ЭлементыФормы.ДокументСписок.ВыделенныеСтроки Цикл
СсылкаНаДокумент = СтрокаСписка.Ссылка;
// Обработка выделенного документа
КонецЦикла;
КонецПроцедуры
Такой подход не требует хранения дополнительных соответствий и полностью опирается на стандартное поведение платформы 1С:Предприятие.