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

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

Разработка на обычных формах в 1С (платформа 8.2 и 8.3) имеет свои специфические особенности, которые часто вызывают затруднения у начинающих программистов. Одна из классических задач — вывод дополнительных расчетных данных в список документов (например, вывод связанного транзакционного документа, склада или статуса) с возможностью быстро перейти в этот объект по двойному клику или нажатию специальной кнопки. В этой статье мы подробно разберем, почему стандартные подходы могут приводить к пустым колонкам на форме, как правильно оптимизировать получение данных без ущерба производительности и как настроить удобное открытие связанных объектов.

Почему колонка на форме остается пустой при заполнении свойства Значение?

Рассмотрим стандартную ситуацию: разработчик добавляет новую колонку в табличное поле списка документов (например, с именем ТранзДокумент), не связывая ее напрямую с реквизитами базы данных (свойство Данные у колонки оставляется пустым). Далее в событии табличного поля ПриПолученииДанных пишется код, который рассчитывает или выбирает из базы нужное значение и записывает его в свойство ячейки Значение:


// Пример проблемного кода
Для Каждого Стр Из ОформленияСтрок Цикл
    Стр.Ячейки.ТранзДокумент.Значение = НайденнаяСсылка;
КонецЦикла;

В процессе отладки программист видит, что ссылка успешно присваивается свойству Значение ячейки, однако на самой форме колонка упорно остается пустой. Почему так происходит? Выясним причину.

В обычных формах 1С за отображение информации в ячейках отвечают два свойства: ОтображатьТекст и ОтображатьЗначение. По умолчанию, если у колонки не заполнено свойство Данные, платформа считает, что в ней должен выводиться только простой текст. При этом свойство ОтображатьТекст установлено в значение Истина, а ОтображатьЗначение — в Ложь. Платформа просто игнорирует записанную в свойство Значение ссылку и пытается отобразить пустую текстовую строку.

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


Ячейка = Стр.Ячейки.ТранзДокумент;
Ячейка.ОтображатьЗначение = Истина; // Включаем отображение значения
Ячейка.Значение = НайденнаяСсылка;

Оптимизация работы ПриПолученииДанных (избавляемся от зависаний списка)

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

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

Для мгновенного поиска вместо метода таблицы значений Найти() (который осуществляет линейный перебор и работает медленно) мы будем использовать объект Соответствие (хеш-таблицу), скорость поиска в котором стремится к O(1).

Разберем оптимальный шаблон реализации события ПриПолученииДанных по шагам:

  1. Сначала мы соберем уникальные ссылки на документы, которые отображаются на экране в данный момент.
  2. Выполним один-единственный запрос к базе данных, передав собранный массив ссылок в качестве параметра.
  3. Заполним временную коллекцию Соответствие, где ключом будет ссылка на основной документ списка, а значением — наш связанный транзакционный документ.
  4. В цикле оформления строк быстро сопоставим данные из Соответствия и выведем их на форму.

Посмотрим на практический пример реализации этого алгоритма:


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

Проблема открытия связанного документа по клику и ее решение через кэширование

Когда колонка заполнена и значения в ней красиво отображаются, возникает следующая задача: пользователь хочет кликнуть дважды по ячейке с транзакционным документом или нажать на нее, чтобы открылась его карточка. Если такая визуализация внедряется для контроля результатов переноса, можно автоматически сверить бухгалтерские и налоговые проводки между базами 1С для быстрого поиска расхождений.

В обычных формах свойство Элемент.ТекущаяСтрока возвращает исключительно данные из основного источника данных списка (строку из БД). Наша добавленная вручную расчетная колонка в ТекущаяСтрока отсутствует. Делать новый запрос в базу данных при каждом клике пользователя — крайне неоптимальный подход, замедляющий реакцию интерфейса на действия пользователя.

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

Разберем по шагам настройку модуля формы:

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

Посмотрим на программную реализацию этой логики:


Перем мКэшТранзДокументов; // Глобальный кэш формы для хранения связей документов

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

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

Интеграция с элементами управления: кнопка открытия в ячейке

Чтобы сделать интерфейс еще более удобным и привычным для пользователя, мы можем добавить в ячейку стандартную кнопку открытия (кнопку с изображением "лупы"). Это явно укажет пользователю на то, что внутри ячейки находится ссылка, на которую можно нажать.

Для реализации этого поведения выполним следующие действия в конфигураторе:

  1. Откроем свойства нашей добавленной колонки ТранзДокумент в редакторе формы.
  2. В свойстве Элемент управления выберем значение ПолеВвода.
  3. Развернем свойства созданного поля ввода и установим флаг Кнопка открытия в значение Да.
  4. Свойство Выбирать тип переведем в значение Нет, если тип связанного документа строго определен.
  5. Создадим обработчик события Открытие для этого элемента управления.

Код для обработки нажатия на кнопку "лупы" в ячейке будет выглядеть следующим образом:


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

Резюме и лучшие практики работы с динамическими колонками

Мы успешно разобрали весь цикл работы с расчетными колонками в обычных формах 1С. Подведем краткие итоги и сформулируем ключевые правила, которые помогут вам избежать распространенных ошибок и гарантируют высокую скорость работы интерфейса:

← На главную