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