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