Как ограничить выбор элементов для «Списка значений» на управляемой форме 1С?

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

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

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

Основные отличия работы со списками значений в обычных и управляемых формах

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

Решение 1: Программная установка ограничения типа для реквизита формы

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

Давайте разберем по шагам, как это реализовать:

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

Посмотрим на пример кода:


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

Важные моменты при реализации:

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

Также автор пытался установить ограничение типа в процедуре МенеджерДоговоровНачалоВыбора с помощью свойств Элемент.ВыбиратьТип = Ложь и Элемент.ОграничениеТипа. Этот подход обычно используется для ограничения выбора при подборе *одиночного* значения в поле ввода, а не для управления типами элементов внутри СпискаЗначений, который уже является коллекцией. Для СпискаЗначений ключевым является именно свойство ТипЗначения самого списка, которое задается программно.

Решение 2: Использование Таблицы формы

Если нам необходимо выбирать несколько значений из справочника, и эти значения должны быть представлены списком, наиболее правильным, гибким и часто рекомендуемым способом в управляемых формах является использование элемента Таблица, а не одиночного Поля, связанного со СпискомЗначений. Этот подход позволяет более наглядно представить список выбранных элементов и предоставляет более удобный интерфейс для пользователя.

Давайте рассмотрим, как это реализуется:

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

Преимущества этого метода:

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

Решение 3: Использование поля ввода с кнопкой выбора из списка (Расширенный вариант)

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

Давайте посмотрим, как это можно сделать:

  1. Основной реквизит на форме: Создаем реквизит формы строкового типа (например, ВыбранныеМенеджерыСтрока), который будет предназначен для отображения выбранных пользователей (например, перечисленных через запятую). Также создаем реквизит формы с типом СписокЗначений (например, ВыбранныеМенеджерыСписок), который будет хранить ссылки на выбранных пользователей.
  2. Размещение поля и кнопки: На форму перетаскиваем строковый реквизит в виде элемента Поле. Рядом с этим полем размещаем кнопку (например, с надписью «Выбрать...»).
  3. Обработчик кнопки: Создаем обработчик нажатия на эту кнопку (например, КнопкаВыбратьМенеджеровНажатие). В этом обработчике мы будем открывать специальную форму подбора.
  4. Форма подбора: Создаем отдельную вспомогательную форму (например, ФормаПодбораПользователей). На этой форме размещаем:
    • ТаблицуЗначений (или динамический список на основе справочника «Пользователи») со списком всех пользователей.
    • Для каждой строки таблицы добавляем колонку с флажком (тип Булево), чтобы пользователь мог отмечать нужных пользователей.
    • Кнопки «ОК» и «Отмена».
  5. Передача данных:
    • При открытии формы подбора (например, в ПриСозданииНаСервере или ПриОткрытии) мы должны передать ей текущий список уже выбранных пользователей из основной формы. Форма подбора должна отобразить эти пользователей с уже установленными флажками.
    • После выбора пользователей на форме подбора и нажатия кнопки «ОК», форма подбора должна вернуть список выбранных элементов в основную форму. Это можно сделать через метод ПоказатьМодальный() с возвращаемым значением, или через методы оповещения (Оповестить()/ОбработкаОповещения()).
  6. Обработка возвращенных данных: В основной форме, после получения списка от выбранных пользователей, программно обрабатываем их:
    • Записываем полученные ссылки в реквизит ВыбранныеМенеджерыСписок.
    • Формируем строковое представление (например, имена пользователей через запятую) и записываем его в реквизит ВыбранныеМенеджерыСтрока, который отображается на форме.

Пример кода для вызова формы подбора из основной формы:


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

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

Пример кода для кнопки «ОК» в форме подбора:


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

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

Заключение

Мы проанализировали проблему ограничения выбора элементов для СпискаЗначений на управляемых формах 1С. Выяснили, что ключевое отличие от обычных форм заключается в необходимости программной установки типа для самого реквизита формы, а не элемента управления. Основное и наиболее простое решение — это использование свойства ТипЗначения для реквизита типа СписокЗначений в процедуре ПриСозданииНаСервере. В качестве более универсального и наглядного подхода для множественного выбора мы рассмотрели использование Таблицы значений с типизированными колонками. А для особо специфичных случаев — реализацию пользовательской формы подбора. Все эти методы позволяют нам эффективно управлять типами данных, хранимых в списках, и предоставлять пользователю удобный и предсказуемый интерфейс.

← На главную