При работе с обычными формами (ОФ) в 1С:Предприятии 8.1 или 8.2 разработчики часто сталкиваются с задачей ограничения прав пользователя на редактирование данных в рамках одной конкретной вкладки. Типичная проблема заключается в том, что если мы просто установим свойство Доступность для всей страницы панели в значение Ложь, пользователь не сможет даже переключиться на эту страницу, чтобы просмотреть информацию. Это делает интерфейс неудобным. Если же перечислять каждый элемент формы вручную в коде, это приводит к загромождению программы и сложностям при дальнейшем сопровождении формы.
В этой статье мы подробно разберем, как решить задачу массового управления состоянием элементов, сохраняя при этом возможность навигации по форме. Мы проанализируем несколько подходов: от программного перебора до архитектурных хитростей в конструкторе форм.
В отличие от управляемых форм, где существует удобная коллекция ПодчиненныеЭлементы, в обычных формах иерархия объектов устроена иначе. Однако у каждого элемента управления есть свойство Родитель, которое указывает на контейнер (панель или страницу), в котором он находится. Разберем, как использовать это свойство для автоматизации нашей задачи.
Для того чтобы сделать все элементы на определенной странице недоступными, мы можем запустить цикл по всей коллекции ЭлементыФормы. Нам нужно сравнить родителя каждого элемента с нашей целевой страницей. Рассмотрим пример кода:
Процедура УстановитьДоступностьЭлементовНаСтранице(ИмяПанели, ИмяСтраницы, Доступность)
ЦелеваяСтраница = ЭлементыФормы[ИмяПанели].Страницы[ИмяСтраницы];
Для Каждого Элемент Из ЭлементыФормы Цикл
Попытка
Если Элемент.Родитель = ЦелеваяСтраница Тогда
// Устанавливаем доступность или режим только чтения
Элемент.Доступность = Доступность;
КонецЕсли;
Исключение
// Некоторые служебные элементы могут не иметь свойства Родитель
Продолжить;
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Этот способ хорош тем, что нам не нужно знать имена всех полей ввода, флажков и кнопок. Достаточно знать только имя панели и имя страницы.
Ситуация усложняется, если на странице панели элементы расположены не «россыпью», а сгруппированы внутри других контейнеров — например, внутри других панелей или рамок групп. В этом случае прямая проверка Элемент.Родитель = ЦелеваяСтраница не сработает для глубоко вложенных объектов, так как их непосредственным родителем будет промежуточный контейнер.
Проанализируем ситуацию и создадим рекурсивную функцию, которая будет проверять всю цепочку родителей вверх до самой формы. Это позволит гарантированно определить, принадлежит ли элемент к выбранной вкладке, независимо от уровня вложенности.
Функция ЭлементПринадлежитСтранице(Элемент, ИскомаяСтраница)
ТекущийРодитель = Элемент.Родитель;
Пока ТекущийРодитель <> Неопределено Цикл
Если ТекущийРодитель = ИскомаяСтраница Тогда
Возврат Истина;
КонецЕсли;
// В обычных формах родителем может быть сама форма, тогда свойство Родитель вернет тип "Форма"
Если ТипЗнч(ТекущийРодитель) = Тип("Форма") Тогда
Прервать;
КонецЕсли;
// Пытаемся подняться выше по иерархии
Попытка
ТекущийРодитель = ТекущийРодитель.Родитель;
Исключение
Прервать;
КонецПопытки;
КонецЦикла;
Возврат Ложь;
КонецФункции
Используя эту функцию в цикле по элементам формы, мы сможем корректно управлять состоянием всей вкладки целиком.
Рассмотрим более простой способ, который не требует написания сложных циклов. Этот метод основан на особенностях поведения объектов в конфигураторе 1С.
Суть заключается в следующем: мы добавляем на нужную страницу основной панели еще одну дополнительную панель (назовем ее ПанельКонтейнер), растягиваем ее на всю площадь страницы и убираем у нее отображение закладок (свойство ОтображатьЗакладки = Ложь). После этого мы размещаем все элементы управления внутри этой новой панели.
Преимущества этого метода:
ЭлементыФормы.ПанельКонтейнер.Доступность = Ложь;.Важный нюанс: при переносе элементов на новую панель в конфигураторе, 1С может автоматически изменить их привязки. Проверьте свойства привязок, чтобы при изменении размеров формы элементы вели себя корректно.
Выясним причину, по которой простое отключение доступности (Доступность = Ложь) не всегда является лучшим решением. Как отмечалось в обсуждении, если на вкладке расположено ТабличноеПоле, то при отключении доступности пользователь теряет возможность прокручивать таблицу (скроллинг). Это критично, если данных много.
Посмотрим на альтернативу в виде свойства ТолькоПросмотр:
Рекомендация: Для полей ввода и табличных частей лучше использовать ТолькоПросмотр = Истина. Однако стоит помнить, что у простых кнопок или флажков свойства ТолькоПросмотр не существует — для них в любом случае придется использовать Доступность = Ложь. При программном переборе элементов обязательно проверяйте наличие свойства, чтобы избежать ошибок выполнения:
Если Найти(Элемент.Метаданные().Имя, "ПолеВвода") > 0 Тогда
Элемент.ТолькоПросмотр = Истина;
Иначе
Элемент.Доступность = Ложь;
КонецЕсли;
Проанализируем еще один подход, который часто применяют опытные разработчики для оптимизации скорости работы формы. Вместо того чтобы каждый раз искать родителя элемента, можно договориться о правилах именования. Например, всем элементам на вкладке «Склад» давать имена, начинающиеся с Склад_ (например, Склад_Количество, Склад_Номенклатура).
В этом случае код блокировки будет максимально простым и быстрым:
Для Каждого Элемент Из ЭлементыФормы Цикл
Если Лев(Элемент.Имя, 6) = "Склад_" Тогда
Элемент.Доступность = Ложь;
КонецЕсли;
КонецЦикла;
Этот метод избавляет от зависимости от структуры панелей и работает быстрее, чем рекурсивный поиск по иерархии объектов Родитель.
Подводя итог, мы разобрали основные способы управления активностью элементов на вкладках обычных форм. Выбор конкретного метода зависит от сложности вашей формы: для простых структур подойдет перебор по родителю, для сложных интерфейсов с таблицами лучше использовать вложенную панель-контейнер и комбинировать свойства Доступность и ТолькоПросмотр.