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

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

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

Метод 1: Использование события «ОбработкаВыбора» (Оперативный контроль)

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

Посмотрим на пример реализации в модуле управляемой формы:


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

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

Важный нюанс: Обратите внимание, что в процедуре ОбработкаВыбора параметр ВыбранноеЗначение передается по ссылке. Если мы просто изменим ВыбранноеЗначение внутри процедуры и оставим СтандартнаяОбработка = Истина, платформа сама присвоит измененное значение в реквизит. Однако, как заметили участники форума, использование СтандартнаяОбработка = Ложь может блокировать выполнение события ПриИзменении. В таком случае вызов обработчика изменения нужно прописывать вручную.

Метод 2: Событие «НачалоВыбора» и «ВыбратьИзСписка» (Превентивный подход)

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

Рассмотрим шаги реализации:

  1. Устанавливаем СтандартнаяОбработка = Ложь, чтобы подавить открытие стандартного списка всех значений перечисления.
  2. Формируем массив или СписокЗначений, содержащий только те элементы, которые разрешены в данный момент.
  3. Вызываем метод ВыбратьИзСписка.

Пример кода для реализации этого подхода:


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

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

Метод 3: Использование свойства «Список выбора»

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

Рассмотрим подробнее: в обработчике ПриИзменении нашей "галочки" мы можем выполнить следующий код:


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

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

Как правильно обнулять значение перечисления?

Выясним причину частой ошибки начинающих программистов. При попытке очистить поле перечисления часто используют Неопределено, 0 или пустую строку "". В 1С реквизит типа ПеречислениеСсылка является строго типизированным.

Запомните:

Пример корректного обнуления:

Объект.Статус = ПредопределенноеЗначение("Перечисление.ИмяВашегоПеречисления.ПустаяСсылка");

Или на стороне сервера:

Объект.Статус = Перечисления.ИмяВашегоПеречисления.ПустаяСсылка();

Безопасность данных: Проверка перед записью

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


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

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

← На главную