Как получить данные из объекта ДокументСписок и реализовать выбор строк в обычных формах 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При работе с обычными формами в 1С:Предприятии начинающие разработчики часто сталкиваются с архитектурными ограничениями динамических списков, таких как ДокументСписок. Типичная задача — добавить в список документов колонку с флажками («галочками»), чтобы пользователь мог отметить несколько документов и выполнить над ними групповое действие (например, групповую рассылку по электронной почте). Попытки напрямую «записать» состояние флажка в строку списка или прочитать данные из «виртуальной» колонки на экране приводят к ошибкам. В этой статье мы подробно разберем, почему так происходит, и рассмотрим три надежных метода решения этой задачи.

Почему стандартный подход «в лоб» не работает?

Для начала проанализируем техническую суть объекта ДокументСписок. Этот объект является динамической выборкой, которая отображает данные напрямую из таблицы базы данных СУБД. Он предназначен исключительно для отображения и динамического считывания информации. Физически в нем нет полей для хранения временных пользовательских данных, таких как пометка выбора.

Вторая проблема связана с так называемыми «виртуальными» колонками. Если мы добавляем в оформление строки (например, через события ПриВыводеСтроки или ПриПолученииДанных) расчетные данные вроде адреса электронной почты, эти данные существуют только в пределах видимой области экрана. Как только пользователь прокручивает список, данные старых строк стираются из оперативной памяти платформы. Попытка обойти строки табличного поля на форме и прочитать значения из ячеек оформления для строк, оставшихся «за кадром», вернет пустое значение. Система просто не хранит состояние невидимых строк.

Для реализации корректного выбора документов и считывания их данных рассмотрим три проверенных практических способа.

---

Способ 1. Использование коллекции в памяти для хранения выбора (Рекомендуемый для ДокументСписок)

Этот способ позволяет сохранить стандартный интерфейс списка документов, но переносит хранение «галочек» из интерфейса в оперативную память компьютера. Мы будем использовать объект Соответствие для хранения связок «Ссылка на документ — Статус выбора (Истина/Ложь)».

Рассмотрим пошагово реализацию этого алгоритма:

  1. Объявление и инициализация коллекции. В самом верху модуля формы в разделе объявления переменных определим нашу коллекцию. Инициализируем ее при открытии формы.

Перем СписокВыбранныхДокументов;

Процедура ПриОткрытии()
    СписокВыбранныхДокументов = Новый Соответствие;
КонецПроцедуры
  1. Настройка колонки на форме. Добавим в табличное поле списка документов новую колонку, назовем ее КолонкаФлажка. Очень важно: свойство «Данные» у этой колонки оставляем абсолютно пустым! Свойство «РежимРедактирования» устанавливаем в значение Непосредственно.
  2. Отображение состояния флажков. Для отрисовки галочек используем обработчик события ПриПолученииДанных табличного поля. Обратите внимание: использовать событие ПриПолученииДанных гораздо эффективнее, чем ПриВыводеСтроки, так как оно обрабатывает строки пакетом, что исключает «зависание» интерфейса при быстрой прокрутке.

Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        // Получаем ссылку на текущий документ строки
        Если ОформлениеСтроки.ДанныеСтроки = Неопределено Тогда
            Продолжить;
        КонецЕсли;
        
        ДокументСсылка = ОформлениеСтроки.ДанныеСтроки.Ссылка;
        
        // Проверяем по нашей коллекции в памяти, отмечен ли данный документ
        ДокументОтмечен = (СписокВыбранныхДокументов.Получить(ДокументСсылка) <> Неопределено);
        
        // Настраиваем отображение флажка в ячейке
        Ячейка = ОформлениеСтроки.Ячейки.КолонкаФлажка;
        Ячейка.ОтображатьТекст = Ложь;
        Ячейка.ОтображатьФлажок = Истина;
        Ячейка.Флажок = ДокументОтмечен;
    КонецЦикла;
КонецПроцедуры
  1. Интерактивное изменение состояния флажка. Нам необходимо обрабатывать клик пользователя по флажку. Для этого перехватим событие ПередНачаломИзменения табличного поля. Если пользователь кликает на колонку флажка, мы отменяем стандартное действие (открытие документа) и инвертируем значение в нашей коллекции.

Процедура ДокументСписокПередНачаломИзменения(Элемент, Отказ)
    Если Элемент.ТекущаяКолонка.Имя = "КолонкаФлажка" Тогда
        Отказ = Истина; // Отменяем открытие формы документа
        
        ТекДанные = Элемент.ТекущиеДанные;
        Если ТекДанные = Неопределено Тогда
            Возврат;
        КонецЕсли;
        
        ТекСсылка = ТекДанные.Ссылка;
        
        // Меняем состояние выбора в нашей коллекции в памяти
        Если СписокВыбранныхДокументов.Получить(ТекСсылка) = Неопределено Тогда
            СписокВыбранныхДокументов.Вставить(ТекСсылка, Истина);
        Else
            СписокВыбранныхДокументов.Удалить(ТекСсылка);
        КонецЕсли;
        
        // Обновляем отображение на форме, чтобы пользователь сразу увидел изменения
        ЭлементыФормы.ДокументСписок.ОбновитьСтроки();
    КонецЕсли;
КонецПроцедуры
  1. Обработка выбранных документов (Рассылка). Теперь при нажатии кнопки отправки мы обходим не строки на форме, а нашу коллекцию в памяти. Для получения адресов электронной почты мы пишем оптимальный запрос к базе данных, получая актуальные контакты контрагентов.

Процедура КнопкаОтправитьНажатие(Кнопка)
    // Собираем массив выбранных ссылок для передачи в запрос
    МассивСсылок = Новый Массив;
    Для Каждого КлючИЗначение Из СписокВыбранныхДокументов Цикл
        МассивСсылок.Добавить(КлючИЗначение.Ключ);
    КонецЦикла;
    
    Если МассивСсылок.Количество() = 0 Тогда
        Предупреждение("Не выбрано ни одного документа для отправки!");
        Возврат;
    КонецЕсли;
    
    // Запросом получаем нужные данные (например, контрагента и его Email)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   РеализацияТоваровУслуг.Ссылка КАК Документ,
        |   РеализацияТоваровУслуг.Контрагент КАК Контрагент,
        |   ПартнерыКонтакты.Значение КАК Email
        |ИЗ
        |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        |   ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК ПартнерыКонтакты
        |       ПО РеализацияТоваровУслуг.Контрагент = ПартнерыКонтакты.Объект
        |       И ПартнерыКонтакты.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты)
        |ГДЕ
        |   РеализацияТоваровУслуг.Ссылка В (&МассивСсылок)";
        
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        Если ЗначениеЗаполнено(Выборка.Email) Тогда
            // Вызываем процедуру отправки почты
            ОтправитьДокументПоПочте(Выборка.Документ, Выборка.Email);
        Иначе
            Сообщить("Для документа " + Выборка.Документ + " не найден Email контрагента!", СтатусСообщения.Внимание);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

---

Способ 2. Использование стандартного множественного выбора платформ (Без флажков)

Если нет жесткого требования выводить именно интерактивные галочки на форму, можно использовать встроенные возможности платформы 1С для множественного выделения строк. Пользователь сможет выбирать строки стандартными клавишами Ctrl или Shift.

Разберем реализацию этого лаконичного механизма:

  1. Установим у табличного поля списка документов свойство «Множественный выбор» в значение Истина.
  2. Добавим кнопку выполнения операции и напишем для нее следующий обработчик:

Процедура КнопкаОтправитьВыделенныеНажатие(Кнопка)
    ВыделенныеСтроки = ЭлементыФормы.ДокументСписок.ВыделенныеСтроки;
    
    Если ВыделенныеСтроки.Количество() = 0 Тогда
        Предупреждение("Пожалуйста, выделите строки в списке документов!");
        Возврат;
    КонецЕсли;
    
    // Формируем массив для передачи в запрос
    МассивДокументов = Новый Массив;
    Для Каждого СтрокаСсылка Из ВыделенныеСтроки Цикл
        МассивДокументов.Добавить(СтрокаСсылка);
    КонецЦикла;
    
    // Получаем почтовые адреса запросом (для производительности)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Реализация.Ссылка КАК Документ,
        |   КИ.Представление КАК Email
        |ИЗ
        |   Документ.РеализацияТоваровУслуг КАК Реализация
        |   ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ
        |       ПО Реализация.Контрагент = КИ.Объект
        |       И КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты)
        |ГДЕ
        |   Реализация.Ссылка В (&МассивДокументов)";
        
    Запрос.УстановитьПараметр("МассивДокументов", МассивДокументов);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        ОтправитьДокументПоПочте(Выборка.Документ, Выборка.Email);
    КонецЦикла;
КонецПроцедуры

---

Способ 3. Переход на «Таблицу значений» в качестве источника данных формы

Проанализируем сценарий, упомянутый автором темы: «обработка создает документы, выводит их на форму, я выбираю нужные...». Если документы создаются программно в рамках этой же сессии работы обработки, использование объекта ДокументСписок в корне неверно. Список документов предназначен для динамического считывания из БД, а здесь нам нужно работать с фиксированным набором только что созданных объектов.

Наиболее правильным, простым и надежным решением будет использование Таблицы значений в качестве источника данных для табличного поля на форме.

Реализуем данный подход по шагам:

  1. На форме создадим табличное поле с типом значения ТаблицаЗначений. Назовем его ТаблицаДокументовНаОтправку.
  2. Добавим в структуру таблицы следующие колонки:
    • Отметка (тип Булево) — для вывода интерактивного флажка;
    • Документ (тип ДокументСсылка) — ссылка на созданный документ;
    • АдресЭлектроннойПочты (тип Строка) — адрес получателя.
  3. При создании документов программно заполняем нашу таблицу значений прямо на форме:

Процедура СоздатьДокументыИЗаполнитьТаблицу()
    // Очищаем старые данные
    ТаблицаДокументовНаОтправку.Очистить();
    
    // Пример цикла генерации документов
    Для Шаг = 1 По 10 Цикл
        НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
        // ... заполнение реквизитов документа ...
        НовыйДок.Записать(РежимЗаписиДокумента.Запись);
        
        // Добавляем информацию в таблицу на форме
        НоваяСтрока = ТаблицаДокументовНаОтправку.Добавить();
        НоваяСтрока.Отметка = Истина; // По умолчанию галочка стоит
        НоваяСтрока.Документ = НовыйДок.Ссылка;
        НоваяСтрока.АдресЭлектроннойПочты = ПолучитьПочтуКонтрагента(НовыйДок.Контрагент);
    КонецЦикла;
    
    // Создаем колонки на форме, если они не были созданы в конфигураторе
    ЭлементыФормы.ТаблицаДокументовНаОтправку.СоздатьКолонки();
КонецПроцедуры
  1. Поскольку это физическая таблица значений, интерактивные галочки в колонке Отметка будут работать автоматически «из коробки» без написания сложных перехватов событий формы. Пользователь сможет легко снимать и устанавливать их прямо на экране.
  2. Код для обработки отправки становится максимально простым, быстрым и понятным:

Процедура КнопкаОтправитьТЗНажатие(Кнопка)
    КоличествоОтправленных = 0;
    
    Для Каждого СтрокаДанных Из ТаблицаДокументовНаОтправку Цикл
        // Проверяем, стоит ли флажок в физической колонке
        Если СтрокаДанных.Отметка Тогда
            Если ЗначениеЗаполнено(СтрокаДанных.АдресЭлектроннойПочты) Тогда
                ОтправитьДокументПоПочте(СтрокаДанных.Документ, СтрокаДанных.АдресЭлектроннойПочты);
                КоличествоОтправленных = КоличествоОтправленных + 1;
            Else
                Сообщить("Не удалось отправить документ " + СтрокаДанных.Документ + ", так как не заполнен Email!", СтатусСообщения.Важное);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Предупреждение("Успешно отправлено писем: " + КоличествоОтправленных);
КонецПроцедуры

Подведем итоги

Для решения задачи выбора строк в 1С:Предприятии на обычных формах всегда оценивайте архитектуру решения. Если вы работаете с журналом документов базы данных, используйте Способ №1 с хранением отметок в Соответствии. Если же ваша обработка сама генерирует документы или выводит фиксированный список для точечной работы, то использование Способа №3 (Таблица значений) значительно сократит время разработки, упростит код и избавит вас от проблем с производительностью интерфейса.

← На главную