Как программно установить отбор в форме списка обычного приложения 1С и запретить пользователю его изменять?

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

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

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

Выясняем причину: почему не работает обращение «через точку»?

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


// Ошибочный вариант, вызывающий исключение
Отбор.Добавить("Ссылка.Ответственный", "Ответственный");

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

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

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

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

  1. С помощью запроса предварительно получить массив или список значений нужных ссылок.
  2. Передать этот массив в отбор с видом сравнения ВСписке.

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


// Правильная установка отбора напрямую по реквизиту
ДокументСписок.Отбор.Ответственный.Установить(ПараметрОтветственный);

Этот код мгновенно отфильтрует список, оставив только документы выбранного сотрудника.

Блокировка изменения отбора пользователем

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

В обычном приложении за отображение списка отвечает элемент формы типа ТабличноеПоле. У этого элемента есть важнейшее свойство — НастройкаОтбора. Именно через него мы можем управлять доступностью интерактивного изменения фильтров.

Разберем по шагам, как заблокировать программный отбор:


// Шаг 1: Устанавливаем сам отбор в данных списка
ФормаСписка.ДокументСписок.Отбор.Ответственный.Установить(ТекущийПользователь);

// Шаг 2: Блокируем элемент интерфейса для пользователя
ФормаСписка.ЭлементыФормы.ДокументСписок.НастройкаОтбора.Ответственный.Доступность = Ложь;

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

Разработка универсального решения

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

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

Ниже представлена готовая функция для поиска табличного поля на форме:


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

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


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

Как использовать разработанное решение

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

Вызов процедуры в модуле формы списка документа (в обработчике события ПриОткрытии) будет выглядеть лаконично и просто:


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

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

← На главную