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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке на платформе 1С:Предприятие 8.2 или 8.3 с использованием Обычных форм программисты часто сталкиваются с задачей отображения дополнительных данных в списках документов. Например, в списке документов РеализацияТоваровУслуг необходимо вывести номер или ссылку на связанный СчетФактураВыданный. Самым производительным способом вывода таких данных считается использование обработчика события ПриПолученииДанных. Однако здесь кроется ловушка: данные, которые мы "рисуем" в ячейках, физически не попадают в объект ТекущаяСтрока. Давайте разберем, почему это происходит и как элегантно решить проблему получения значения при двойном клике или нажатии кнопки выбора.

Выясним причину: почему данные отсутствуют в ТекущаяСтрока

Проанализируем механизм работы табличного поля в Обычных формах. Когда платформа отрисовывает список, она вызывает событие ПриПолученииДанных. В этот момент нам доступна коллекция ОформленияСтрок, где для каждой видимой на экране строки мы можем программно установить значение в ячейку. Мы пишем код вроде ОформлениеСтроки.Ячейки.СчетФактура.Значение = НайденнаяСсылка;. Визуально в таблице всё выглядит прекрасно, но как только мы пытаемся обратиться к Элемент.ТекущаяСтрока.СчетФактура в событии Выбор, мы получаем пустоту или ошибку.

Это происходит потому, что ТекущаяСтрока возвращает данные из источника данных (например, из динамического списка или таблицы значений), а не из объекта оформления. Объект ОформлениеСтроки — это временный "слой" визуализации, который существует только в момент отрисовки. Платформа не сохраняет эти значения обратно в базу или в кэш списка. Таким образом, чтобы "достать" документ из такой ячейки, нам нужно либо запросить его заново, либо заранее позаботиться о хранении этих связей.

Решение 1: Повторный запрос в обработчике выбора

Самый простой, но не всегда самый быстрый метод — выполнить запрос к базе данных непосредственно в момент выбора строки. Рассмотрим этот вариант подробнее. Предположим, пользователь дважды щелкнул по строке. В обработчике события Выбор мы можем определить, по какой колонке был произведен клик, и, если это наша динамическая колонка, выполнить поиск связанного документа.

Посмотрим на пример реализации такого подхода:


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

Важный момент: данный метод надежен, но создает лишнюю нагрузку на сервер БД при каждом клике. Если база "тяжелая", а запросы сложные, пользователь может ощутить задержку.

Решение 2: Кеширование данных через Соответствие (Рекомендуемый способ)

Проанализируем более профессиональный подход. Чтобы не дергать базу данных дважды (один раз при выводе списка и второй раз при клике), мы можем использовать кеширование на уровне модуля формы. Для этого мы создадим переменную, которая будет хранить соответствие между ссылкой на реализацию и ссылкой на счет-фактуру.

Разберем реализацию по шагам:

  1. Объявим переменную в самом верху модуля формы.
  2. В обработчике ПриПолученииДанных будем наполнять это соответствие.
  3. В обработчике Выбор будем мгновенно извлекать значение из памяти.

Посмотрим на программный код:


Перем КэшСчетовФактур; // Объявляем переменную в начале модуля

Процедура ПриОткрытии()
    // Инициализируем коллекцию
    КэшСчетовФактур = Новый Соответствие;
КонецПроцедуры

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

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

Нюансы настройки колонки в конфигураторе

Рассмотрим еще один важный аспект. Чтобы работа с ОформлениеСтроки.Ячейки.ИмяКолонки.Значение проходила корректно, рекомендуется в свойствах колонки табличного поля в конфигураторе явно указать Тип значения. Если тип будет "Произвольный", система может некорректно обрабатывать методы открытия формы или представления объекта.

Также стоит помнить, что в Обычных формах событие ПриПолученииДанных может вызываться очень часто (при скроллинге, изменении размеров окна). Использование кеша Соответствие позволяет избежать повторных запросов к одним и тем же данным внутри одного сеанса отрисовки, что значительно ускоряет работу интерфейса.

Сравнение с Управляемыми формами

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

Подведем итог: Для Обычных форм связка "Запрос в ПриПолученииДанных + хранение в переменной Соответствие" является "золотым стандартом". Она обеспечивает и визуальную наполненность списка, и моментальную реакцию на действия пользователя без избыточной нагрузки на сервер.

← На главную