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

Программист IT и автоматизация бизнеса
← На главную

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

Разберем причину ошибки «Поле объекта не доступно для записи (Родитель)»

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


// ОШИБОЧНЫЙ КОД
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.Родитель = ГруппаОтбора; // Здесь возникнет ошибка

Проанализируем ситуацию: в системе компоновки данных (СКД) иерархия элементов строится не через присвоение свойства Родитель, а через добавление элемента непосредственно в коллекцию Элементы конкретной группы. Если нам нужно поместить отбор внутрь группы (например, чтобы объединить условия по «ИЛИ»), мы должны вызывать метод Добавить() у коллекции элементов этой группы.

Рассмотрим правильный подход к созданию иерархического отбора:


// ПРАВИЛЬНЫЙ КОД
// 1. Добавляем группу в основной отбор
ГруппаИЛИ = Список.Отбор.Эelements.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;

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

Выясним причину ошибки «Невозможно применить фиксированные настройки. Пересекаются элементы отбора»

Это, пожалуй, самая коварная ошибка при работе с динамическими списками. Она возникает из-за того, что в динамическом списке существует несколько «слоев» настроек, которые платформа пытается объединить перед выполнением запроса к базе данных:

  1. Фиксированные настройки (FixedSettings): устанавливаются только программно, пользователь их не видит и не может изменить.
  2. Пользовательские настройки (UserSettings): то, что пользователь ввел через форму «Настройка списка» или вынес в «Быстрые отборы».
  3. Основные настройки (Settings): базовый слой настроек компоновщика.

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

Чтобы избежать этой ошибки, проанализируем следующие стратегии:

1. Очистка перед установкой: перед добавлением новых элементов стоит очистить существующие, если это допустимо бизнес-логикой. Используем метод Список.Отбор.Элементы.Очистить(). Однако помните, что это очистит только текущий программный слой.

2. Использование параметров запроса: если отбор должен быть жестким (например, пользователь вообще не должен видеть чужие документы), лучше реализовать это через параметры в тексте запроса динамического списка (ГДЕ Исполнитель = &ТекущийИсполнитель). Это исключает саму возможность пересечения на уровне компоновщика.

Установка отбора через КомпоновщикНастроек

Рассмотрим более гибкий способ управления отборами через КомпоновщикНастроек. Это позволяет управлять тем, будет ли отбор виден пользователю и сможет ли он его менять. Посмотрим на пример кода:


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

Использование стандартных функций БСП

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

Разберем ее преимущества:

Пример вызова функции БСП:


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

Где лучше устанавливать отбор: ПриСозданииНаСервере или ПриОткрытии?

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

  1. Минимизация вызовов: Установка отбора на сервере происходит до того, как данные первый раз полетят на клиент. Если устанавливать отбор ПриОткрытии (на клиенте), список сначала загрузится без отбора, а потом сразу пересчитается (произойдет лишний запрос к базе).
  2. Доступ к данным: На сервере у нас есть прямой доступ к реквизитам базы данных и параметрам сеанса без лишних контекстных вызовов.

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

Важный нюанс: при использовании пользовательских настроек (которые сохраняются автоматически при закрытии формы), важно помнить о событии ПриЗагрузкеДанныхИзНастроекНаСервере. Если ваш программный код конфликтует с тем, что система «вспомнила» о предпочтениях пользователя из прошлого сеанса, именно в этом обработчике следует финально корректировать отборы.

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

← На главную