При разработке интерфейсов на управляемых формах часто возникает задача динамического ограничения прав пользователя на выбор того или иного значения. В случае с обычным полем ввода это решается достаточно просто, но когда мы используем поле переключателя (Radio buttons), возникают определенные трудности. Стандартное ожидание разработчика — сделать один из пунктов «сереньким» и недоступным для клика — наталкивается на особенности реализации платформы 1С:Предприятие 8.3.
В этой статье мы подробно разберем, почему стандартные методы не всегда работают так, как ожидается, и проанализируем несколько проверенных способов решения этой задачи: от манипуляций со списком выбора до полной замены переключателя более гибкими элементами управления.
На первый взгляд кажется, что решение лежит на поверхности — использование свойства ДоступныеЗначения у элемента формы. Однако давайте разберем, почему это не дает нужного визуального эффекта. Проанализируем поведение платформы при установке этого свойства на сервере.
Если мы попытаемся ограничить список доступных значений программно, код может выглядеть следующим образом:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Заполняем основной список выбора
Элементы.ПолеСтатус.СписокВыбора.Добавить("Новый", "Новый статус");
Элементы.ПолеСтатус.СписокВыбора.Добавить("ВРаботе", "В работе");
Элементы.ПолеСтатус.СписокВыбора.Добавить("Заблокирован", "Заблокирован");
// Пытаемся ограничить доступные значения
ОграниченныйСписок = Новый СписокЗначений;
ОграниченныйСписок.Добавить("Новый");
ОграниченныйСписок.Добавить("ВРаботе");
Элементы.ПолеСтатус.СписокВыбора.ДоступныеЗначения = ОграниченныйСписок;
КонецПроцедуры
Что увидит пользователь? К сожалению, визуально переключатель никак не изменится. Все пункты останутся активными на вид. При попытке нажать на «Заблокирован», значение в реквизите просто не установится или сбросится в пустое значение. Это вводит пользователя в заблуждение, так как он не понимает, почему кнопка нажимается, но ничего не происходит. Более того, свойство ДоступныеЗначения может некорректно синхронизироваться между сервером и клиентом, что делает этот метод ненадежным для управления интерфейсом.
Рассмотрим более действенный метод. Если нам нужно запретить выбор значения в зависимости от условий (например, от роли пользователя или состояния другого поля), мы можем просто удалять или добавлять элементы в СписокВыбора.
Разберем алгоритм по шагам:
ПриИзменении связанного поля) вызываем серверный контекст.СписокВыбора переключателя.Посмотрим на пример кода:
&НаСервере
Процедура ОбновитьСписокВыбораНаСервере()
Список = Элементы.ПолеПереключатель.СписокВыбора;
Список.Очистить();
Список.Добавить(Пречисления.Статусы.Активен, "Активен");
// Условие: только администратор может ставить спец-статус
Если РольДоступна("ПолныеПрава") Тогда
Список.Добавить(Пречисления.Статусы.Архив, "Архив");
КонецЕсли;
КонецПроцедуры
Важный нюанс: Если в реквизите уже было выбрано значение, которое вы удаляете из списка, поле на форме может отобразиться как пустое. Перед удалением обязательно проверяйте текущее значение реквизита и, если оно становится недопустимым, принудительно меняйте его на разрешенное по умолчанию.
Если ваша задача — именно показать пользователю, что значение существует, но оно «серое» (недоступное), то стандартный переключатель нам не подходит. Профессиональным обходом является использование Группы кнопок.
Разберем, как это реализовать:
РежимПроверки (чтобы кнопки вели себя как переключатели).Доступность.Выясним преимущества этого подхода: кнопки в режиме фиксации выглядят как современный переключатель, и при установке Доступность = Ложь кнопка действительно становится бледной и не реагирует на нажатия. Программное управление будет выглядеть так:
&НаКлиенте
Процедура УправлениеДоступностьюКнопок(УсловиеРазрешено)
// Кнопка 1 всегда доступна
Элементы.КнопкаСтатусНовый.Доступность = Истина;
// Кнопка 2 зависит от условий
Элементы.КнопкаСтатусАрхив.Доступность = УсловиеРазрешено;
КонецПроцедуры
При нажатии на любую из кнопок необходимо в обработчике прописывать изменение основного реквизита и визуально «нажимать» кнопку через свойство Пометка.
Проанализируем ситуацию, описанную в сообщении №16 форума. Автор предлагает интересный «костыль», который отлично работает визуально. Если значение должно стать недоступным, мы удаляем его из основного переключателя и одновременно включаем видимость другого элемента — Декорации или Надписи, которая имитирует этот пункт переключателя, но окрашена в серый цвет.
Этот метод хорош тем, что не требует переписывания всей логики формы на кнопки. Мы просто создаем рядом с переключателем «статичный муляж» недоступного пункта и управляем его видимостью синхронно с составом СпискаВыбора основного поля.
Если требования к дизайну максимально строгие и вам нужны именно классические «кружочки» (Radio buttons), где один из них должен быть заблокирован, можно прибегнуть к использованию Поля HTML-документа. Это позволяет отрисовать любой интерфейс.
Разберем по шагам логику реализации:
ПолеHTMLДокумента.<input type="radio">.disabled.ПриНажатии в 1С, куда HTML-страница передает данные через схему v8action.Пример формирования строки для HTML-поля:
ТекстHTML = "
|<html>
|<body>
| <input type='radio' name='stat' value='1' checked> Активен<br>
| <input type='radio' name='stat' value='2' disabled> <span style='color:gray;'>Заблокирован</span>
|</body>
|</html>";
Хотя этот метод требует больше времени на реализацию, он дает 100% контроль над визуализацией каждого отдельного пункта переключателя.
Подводя итог, можно сказать, что стандартное поле переключателя в 1С не предназначено для тонкой настройки доступности отдельных элементов списка. Если вам достаточно просто скрыть лишнее — используйте динамическое изменение СпискаВыбора. Если же критически важно показать пользователю заблокированный пункт — оптимальным выбором будет Группа кнопок или использование Декораций для имитации недоступного значения.
Помните, что интерфейс должен быть интуитивно понятным: если значение недоступно, пользователь должен сразу видеть это по его цвету, а не догадываться об этом после неудачного клика.