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

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

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

Проблема, с которой столкнулся автор, заключается в двух моментах:

  1. Необходимо показать пользователю не все значения перечисления, а только определенный, отфильтрованный набор.
  2. При попытке использовать для этого стандартный механизм (свойство поля СписокВыбора и обработчик НачалоВыбораИзСписка), поле ввода на форме становится пустым при открытии, хотя связанный с ним реквизит данных заполнен.

Проанализируем ситуацию и найдем правильное решение.

Почему поле на форме становится пустым?

Это ключевой момент, который нужно понять. Когда вы для элемента формы (поля ввода) устанавливаете режим выбора из списка и программно управляете этим списком через свойство СписокВыбора, платформа 1С при отрисовке формы выполняет простую проверку: "Присутствует ли текущее значение реквизита в предоставленном списке выбора?".

Если ответ "Да", платформа находит соответствующий элемент в списке и отображает его представление (например, "Активен", "Завершен").

Если ответ "Нет", платформа не может найти соответствие. Она не знает, какое представление показать для значения, которого нет в разрешенном списке. В результате, чтобы не вводить пользователя в заблуждение, она отображает поле как пустое. Хотя на уровне данных, в реквизите объекта, значение по-прежнему хранится.

Именно это и произошло в сообщении (2): список для выбора формируется, но в него не попадает уже сохраненное значение, из-за чего при открытии формы мы видим пустоту.

Решение 1: Правильное использование свойства "СписокВыбора" при открытии формы

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

  1. Создаем обработчик события формы ПриОткрытии(). Именно в этот момент нам нужно подготовить все элементы формы к отображению.

  2. Формируем список разрешенных значений. Внутри обработчика создаем новый объект СписокЗначений и заполняем его теми значениями перечисления, которые должны быть доступны пользователю для выбора.

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

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

    Важно: даже если вы добавите "запрещенное" значение для отображения, пользователь не сможет его выбрать, если вы будете переформировывать список в событии НачалоВыбора (см. Решение 2).

  4. Присваиваем готовый список элементу формы. Последний шаг — присвоить наш подготовленный СписокЗначений свойству СписокВыбора нужного поля ввода.

    
    // Завершение кода в процедуре ПриОткрытии()
    
        // Находим нужный элемент на форме и устанавливаем ему список выбора
        ЭлементыФормы.СтатусЗаказа.СписокВыбора = ОграниченныйСписок;
    
    КонецПроцедуры
    

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

Решение 2: Динамическое формирование списка в момент выбора

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

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


// Обработчик события "НачалоВыбора" для поля ввода "СтатусЗаказа"
Процедура СтатусЗаказаНачалоВыбора(Элемент, СтандартнаяОбработка)

    // Запрещаем стандартное поведение платформы (открытие полного списка перечисления)
    СтандартнаяОбработка = Ложь;

    // Создаем и заполняем список заново, на основе текущих условий
    СписокДляВыбора = Новый СписокЗначений;

    // Пример динамического условия
    Если ЭтотОбъект.СуммаДокумента > 100000 Тогда
        // Для крупных заказов доступны особые статусы
        СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.НаСогласовании);
        СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Согласован);
    Иначе
        // Для обычных заказов
        СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Новый);
        СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);
    КонецЕсли;

    СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Отменен); // Этот статус доступен всегда

    // Присваиваем обновленный список элементу формы
    Элемент.СписокВыбора = СписокДляВыбора;

КонецПроцедуры

При таком подходе пользователь при каждом открытии списка выбора будет видеть только актуальные для текущего контекста значения.

Альтернативный подход: Несвязанное поле ввода

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

  1. Создайте на форме новый реквизит, не связанный с данными (например, ВыбранныйСтатус с тем же типом "Перечисление").
  2. Разместите на форме поле ввода и свяжите его с этим новым реквизитом ВыбранныйСтатус.
  3. Для этого поля настройте СписокВыбора, как описано в решениях выше. При открытии формы копируйте в него значение из основного реквизита: ВыбранныйСтатус = ЭтотОбъект.СтатусЗаказа.
  4. Создайте для поля обработчик события ПриИзменении.
  5. В этом обработчике программно присваивайте выбранное значение основному реквизиту данных: ЭтотОбъект.СтатусЗаказа = ВыбранныйСтатус.

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

Минусы: больше кода, нужно вручную синхронизировать данные между реквизитом формы и реквизитом объекта, что может привести к ошибкам, если что-то упустить.

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

← На главную