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

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

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

Выясним причину: почему простое изменение свойств отбора не обновляет список?

Рассмотрим типичный сценарий. В форме выбора справочника присутствует динамический список. Нам необходимо реализовать команду, которая будет переключать видимость неактуальных элементов (например, по булевому реквизиту Актуальность). Разработчик пишет простой обход коллекции элементов отбора на сервере:


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

На клиенте вызывается метод Элементы.Список.Обновить() или даже ЭтаФорма.ОбновитьОтображениеДанных(), но интерфейс не реагирует. Почему так происходит?

Дело в особенностях работы объекта КомпоновщикНастроек. Платформа 1С спроектирована таким образом, что непосредственное изменение свойств объектов внутри коллекции (например, флага Использование у элемента отбора) происходит локально в памяти, но не генерирует внутреннее событие изменения для самого динамического списка. Сам по себе список «не знает», что где-то глубоко внутри коллекции настроек поменялось значение. Чтобы изменения вступили в силу, СУБД должна получить новый SQL-запрос с измененным условием ГДЕ, а для этого платформа должна явно перестроить схему компоновки.

Для того чтобы компоновщик «увидел» изменения и инициировал обновление данных, необходимо выполнить принудительную загрузку измененных настроек обратно в компоновщик с помощью метода ЗагрузитьНастройки().

Решение 1. Классический метод с переприсвоением настроек

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

Рассмотрим правильный вариант реализации серверной процедуры:


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

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

Решение 2. Учет иерархии настроек (Пользовательские настройки)

Иногда даже применение метода ЗагрузитьНастройки() не решает проблему. Это связано с тем, что в Системе компоновки данных (СКД) существует строгая иерархия настроек, имеющих разный приоритет:

  1. ФиксированныеНастройки — жестко заданные программно настройки. Пользователь не имеет к ним доступа. Обладают наивысшим приоритетом.
  2. ПользовательскиеНастройки — настройки, которые выведены на форму (например, быстрые отборы) или доступны пользователю через стандартное меню «Настроить список». Имеют приоритет над обычными настройками!
  3. Настройки — базовые настройки по умолчанию, заданные разработчиком в конфигураторе.

В чем кроется ловушка? Если в конфигураторе для отбора «Актуальность» было включено свойство «Включать в пользовательские настройки», то любые программные изменения в коллекции Список.КомпоновщикНастроек.Настройки.Отбор будут попросту проигнорированы платформой. Значение из базовых настроек будет перекрыто значением, хранящимся в пользовательских настройках.

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


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

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

Решение 3. Современный стандарт разработки (использование БСП)

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

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


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

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


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

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

Разберем разницу между методами обновления данных

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

  1. Элементы.ИмяСписка.Обновить() — этот метод заставляет динамический список принудительно обратиться к базе данных (СУБД) за актуальной порцией записей. Это необходимо, если данные физически изменились в базе данных (например, параллельно другой пользователь изменил наименование элемента справочника или провел документ), но при этом структура и параметры самих отборов динамического списка не менялись.
  2. ЭтаФорма.ОбновитьОтображениеДанных() — выполняет исключительно визуальное обновление элементов управления на клиенте (перерисовывает форму). Метод не делает запросов к базе данных за новыми записями. Он нужен, например, для того, чтобы платформа заново рассчитала условное оформление строк динамического списка, которые уже отображены на экране.
  3. ОповеститьОбИзменении(Тип) — глобальный метод платформы. Он отправляет оповещение всем открытым формам о том, что данные указанного типа были изменены. Все активные динамические списки, у которых основная таблица совпадает с этим типом данных, автоматически инициируют перезапрос к БД. Применять его локально просто для переключения одной кнопки-флажка на форме — избыточно, так как это создает дополнительную нагрузку на сервер за счет обновления всех открытых окон пользователя.

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

← На главную