Почему не обновляется динамический список после установки отбора и как это исправить?

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

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

Анализируем исходный код и выявляем причину ошибки

Для начала проанализируем типичный пример кода, в котором совершена эта ошибка. В обработчике события СписокТиповПриАктивизацииСтроки на клиенте вызывается серверный метод для установки отбора:


&НаКлиенте
Процедура СписокТиповПриАктивизацииСтроки(Элемент)
    УстановитьОтборПодчиненныхСправочниковНаФорме(Элемент.ТекущаяСтрока, СписокМоделей);
    Элементы.СписокМоделей.Обновить();    
КонецПроцедуры

На сервере разработчик пытается применить отбор через неконтекстную процедуру:


&НаСервереБезКонтекста
Процедура УстановитьОтборПодчиненныхСправочниковНаФормеНаСервере(Владелец, ДинамическийСписокФормы)
    ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(ДинамическийСписокФормы, "Владелец", Владелец, ВидСравненияКомпоновкиДанных.Равно,,Истина,РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный);
КонецПроцедуры

Почему же эта конструкция не работает? Все дело в директиве компиляции &НаСервереБезКонтекста и механизмах передачи параметров между клиентом и сервером:

  1. Передача по значению (копирование). Когда мы вызываем процедуру с директивой &НаСервереБезКонтекста и передаем туда реквизит формы (в нашем случае динамический список СписокМоделей), платформа сериализует этот объект и создает его временную копию на сервере. Изменения, которые вносит процедура общего модуля БСП в параметр ДинамическийСписокФормы, происходят только в рамках этой локальной копии на сервере.
  2. Отсутствие обратной связи. Поскольку вызов является внеконтекстным, измененная копия динамического списка не возвращается обратно на клиент и не синхронизируется с реквизитом формы. После завершения работы процедуры все изменения просто уничтожаются в памяти сервера. Наш исходный список на форме остается нетронутым.
  3. Особенности сериализации динамического списка. Объект типа ДинамическийСписок в принципе не предназначен для передачи во внеконтекстные методы. Платформа 1С в данном случае не генерирует исключение, а молча передает «отвязанный» компоновщик настроек, из-за чего визуально код отрабатывает без ошибок, но результат равен нулю.

Решение 1. Установка отбора непосредственно на клиенте (Рекомендуемое)

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

Перепишем наш клиентский метод следующим образом:


&НаКлиенте
Процедура СписокТиповПриАктивизацииСтроки(Элемент)
    
    // Устанавливаем отбор напрямую на клиенте без обращения к серверу
    ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
        СписокМоделей, 
        "Владелец", 
        Элемент.ТекущаяСтрока, 
        ВидСравненияКомпоновкиДанных.Равно, , 
        Истина, 
        РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный
    );
    
КонецПроцедуры

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

Решение 2. Использование контекстного серверного вызова

Если в процессе установки отбора вам обязательно требуется выполнить какую-либо сопутствующую сложную серверную логику (например, запросить дополнительные данные из базы данных), то процедуру установки отбора необходимо сделать контекстной.

В контекстных процедурах с директивой &НаСервере нам доступен весь контекст формы. Нам не нужно передавать динамический список в качестве параметра — мы можем обращаться к нему напрямую как к реквизиту формы:


&НаКлиенте
Процедура СписокТиповПриАктивизацииСтроки(Элемент)
    УстановитьОтборНаСервере(Элемент.ТекущаяСтрока);
КонецПроцедуры

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

При таком подходе платформа автоматически синхронизирует состояние реквизитов формы между клиентом и сервером при возврате управления на клиентскую сторону.

Куда именно устанавливается отбор? Разбираемся в настройках компоновщика

При работе с динамическими списками критически важно понимать, в какой именно раздел компоновщика настроек попадает наш отбор. Метод БСП УстановитьЭлементОтбораДинамическогоСписка управляет этим поведением с помощью последнего параметра — режима отображения элемента.

Рассмотрим детально, как это работает:

  1. Фиксированные настройки. Если мы передаем режим отображения Недоступный, то отбор помещается в коллекцию КомпоновщикНастроек.ФиксированныеНастройки.Отбор. Такие отборы жестко накладываются на уровне платформы. Пользователь не сможет увидеть данный фильтр в стандартном окне настройки списка, а также не сможет его случайно отключить или изменить. Это идеальный вариант для реализации связи «главный — подчиненный справочник».
  2. Пользовательские настройки. Если мы используем режимы отображения БыстрыйДоступ или Обычный, отбор помещается в пользовательские настройки. В этом случае пользователь видит наложенный фильтр и может управлять им вручную.

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

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

Давайте сформулируем правила оптимизации этой логики:

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


&НаКлиенте
Перем ТекущийВладелецДляОтбора;

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

&НаКлиенте
Процедура ПрименитьОтборСЗадержкой()
    // Процедура сработает только после паузы в действиях пользователя
    УстановитьОтборНаСервере(ТекущийВладелецДляОтбора);
КонецПроцедуры

Благодаря такому подходу интерфейс вашего приложения останется плавным и быстрым даже при работе через медленное интернет-соединение.

← На главную