Как программно определить, проведен ли документ, в форме списка управляемого приложения 1С 8.3?

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

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

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

Постановка задачи и анализ проблемы производительности

Рассмотрим ситуацию: у нас есть форма списка документов. Нам необходимо при активизации каждой строки мгновенно определять, проведен ли выбранный документ, и на основании этого управлять видимостью кнопки печати на командной панели. Основная проблема управляемых форм заключается в минимизации трафика между клиентом и сервером. По умолчанию платформа передает с сервера на клиент только те данные динамического списка, которые непосредственно отображаются в колонках на форме.

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

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

Давайте разберем правильные, оптимизированные методы решения этой задачи.

Метод 1. Использование свойства «Использовать всегда» (Рекомендуемый способ)

Для того чтобы значение реквизита Проведен было доступно на клиенте без обращения к серверу, нам необходимо принудительно включить его в кэш строки динамического списка. Для этого в платформе существует специальное свойство поля — «Использовать всегда».

Выполнить эту настройку можно двумя способами:

Способ А. Настройка в конфигураторе:

  1. Откройте управляемую форму списка документов.
  2. Перейдите на вкладку «Реквизиты» и найдите ваш динамический список (обычно с именем Список).
  3. Откройте свойства списка и найдите поле «Настройка списка» -> «Поля».
  4. Найдите в списке полей реквизит Проведен.
  5. Установите для этого поля флаг «Использовать всегда».

Способ Б. Программная настройка при создании формы:

Если вы предпочитаете настраивать интерфейс программно или динамический список формируется динамически, вы можете установить это свойство в серверном обработчике формы ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Указываем платформе, что поле "Проведен" необходимо передавать на клиент всегда
    Список.УстановитьОбязательноеИспользование("Проведен", Истина);
    
КонецПроцедуры

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

Теперь мы можем написать быстрый и безопасный обработчик события активизации строки таблицы списка:


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

В данном примере мы используем обращение к свойству ТекущиеДанные, которое содержит структуру полей текущей строки, уже переданную на клиент. Никаких серверных вызовов при этом не происходит, интерфейс работает плавно и мгновенно реагирует на действия пользователя.

Почему событие «ПриПолученииДанныхНаСервере» не подходит для этой задачи?

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

Событие ПриПолученииДанныхНаСервере предназначено исключительно для:

Это событие вызывается для целой порции (пачки) строк, которые выводятся на экран монитора пользователя. Попытка управлять видимостью элементов управления *самой формы* (командной панели, отдельных кнопок) внутри этого события приведет к следующим проблемам:

Таким образом, для изменения состояния элементов управления формы при смене активного документа всегда следует использовать клиентское событие таблицы ПриАктивизацииСтроки в связке со свойством Использовать всегда.

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

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

В составе БСП присутствует мощная подсистема «Печать», которая автоматически решает все задачи по выводу команд печати на форму и контролю проведения документов.

Разберем по шагам, как это реализуется в БСП:

  1. В модуле менеджера вашего документа описывается процедура ДобавитьКомандыПечати(СписокКоманд).
  2. При добавлении команды печати в коллекцию вы можете указать параметр ПроверкаПроведенияПередПечатью.

Рассмотрим пример кода в модуле менеджера документа:


Процедура ДобавитьКомандыПечати(СписокКоманд) Экспорт
    
    // Создаем новую команду печати
    Команда = СписокКоманд.Добавить();
    Команда.Идентификатор = "ОфициальныйМакет";
    Команда.Представление = НСтр("ru = 'Официальный документ (с подписью)'");
    Команда.ВыводитьВСписок = Истина;
    
    // Важнейший параметр для нашей задачи:
    // БСП автоматически проверит проведение документа перед выводом на печать
    Команда.ПроверкаПроведенияПередПечатью = Истина;
    
КонецПроцедуры

Что произойдет при использовании этого механизма?

Резюме и рекомендации

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

← На главную