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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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


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

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

Заключение

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

← На главную