В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача: ограничить пользователю возможность редактирования документа (например, «Реализация товаров и услуг»), но при этом оставить доступными несколько конкретных полей (например, «Дата отгрузки» или «Комментарий») и сохранить функциональность кнопок проведения. Разберем, почему стандартные подходы не всегда работают и как правильно реализовать эту логику на управляемых формах.
Рассмотрим ситуацию, с которой сталкиваются многие разработчики: при попытке заблокировать всю форму или обойти элементы в цикле, либо блокируется абсолютно всё (включая нужные поля), либо форма остается полностью доступной. Основная причина кроется в иерархической структуре элементов управляемой формы. Если вы устанавливаете Доступность = Ложь для группы (родительского элемента), то все дочерние элементы внутри этой группы автоматически становятся недоступными, даже если вы явно пропишете для них Доступность = Истина в коде ниже.
Проанализируем основные свойства, которые отвечают за запрет редактирования:
Ложь, элемент становится «серым», его нельзя выделить, из него нельзя скопировать текст, и он полностью исключается из взаимодействия.Истина, данные в поле нельзя изменить, но их можно выделить и скопировать. Это более «мягкий» вариант ограничения, который предпочтителен для полей ввода.Наиболее гибкий способ — это перебор всех элементов формы в цикле. Однако, чтобы не «убить» доступность нужных нам полей, мы должны игнорировать группы элементов (контейнеры) и менять состояние только у конечных полей ввода или кнопок. Выясним, как это реализовать правильно.
Рассмотрим пример кода, который можно разместить в процедуре ПриЧтенииНаСервере или ПриСозданииНаСервере:
&НаСервере
Процедура ЗаблокироватьРеквизитыНаСервере()
// Определим список имен элементов, которые ДОЛЖНЫ остаться доступными
Исключения = Новый Массив;
Исключения.Добавить("ДатаОтгрузки");
Исключения.Добавить("Комментарий");
Исключения.Добавить("ЗаписатьИПровести"); // Не забываем про кнопку проведения
Для Каждого Элемент Из ЭтаФорма.Элементы Цикл
// Проверяем, не входит ли элемент в список исключений
Если Исключения.Найти(Элемент.Имя) <> Неопределено Тогда
Продолжить;
КонецЕсли;
// Важный момент: не блокируем группы, иначе заблокируются вложенные в них исключения
Если ТипЗнч(Элемент) = Тип("ГруппаФормы") Тогда
Продолжить;
КонецЕсли;
// Устанавливаем ограничение в зависимости от типа элемента
Попытка
Если ТипЗнч(Элемент) = Тип("ПолеФормы") Тогда
Элемент.ТолькоПросмотр = Истина;
Иначе
Элемент.Доступность = Ложь;
КонецЕсли;
Исключение
// Обработка элементов, не имеющих данных свойств
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Современный и наиболее производительный метод для управляемых форм — это Условное оформление. Оно работает на уровне платформы и позволяет динамически управлять свойствами элементов без написания сложных циклов. Посмотрим, как настроить его программно.
Этот метод хорош тем, что он автоматически обрабатывает появление новых элементов на форме и работает быстрее, чем ручной перебор коллекции Элементы.
&НаСервере
Процедура НастроитьУсловноеОформление()
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Устанавливаем само оформление
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ТолькоПросмотр", Истина);
// 2. Условие: например, если роль пользователя "Кладовщик"
// Или если документ уже проведен
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Проведен");
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.ПравоеЗначение = Истина;
// 3. Указываем, какие поля оформлять (все, кроме исключений)
// Здесь придется перечислить те поля, которые мы ХОТИМ заблокировать
Для Каждого Элемент Из ЭтаФорма.Элементы Цикл
Если ТипЗнч(Элемент) = Тип("ПолеФормы") И Элемент.Имя <> "ДатаОтгрузки" Тогда
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(Элемент.Имя);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Существует самый быстрый способ заблокировать документ — установить ЭтаФорма.ТолькоПросмотр = Истина. Это свойство блокирует все данные, связанные с основным реквизитом Объект. Однако у этого метода есть два существенных недостатка для нашей задачи:
Объект.ДатаОтгрузки внутри формы в режиме «Только просмотр» невозможно.Решение: Если вы используете этот метод, то поля, которые должны остаться доступными, не должны быть связаны с путем к данным Объект... напрямую, либо они должны управляться через дополнительные реквизиты формы, что усложняет логику записи. Поэтому для выборочной блокировки лучше использовать Способ 1.
Проанализируем ситуацию с местом вызова кода. Крайне не рекомендуется использовать событие ПриОткрытии на клиенте для таких манипуляций. Рассмотрим почему:
ПриОткрытии (клиент) проверка ролей через РольДоступна() требует серверного вызова.Правильнее всего использовать серверный обработчик ПриЧтенииНаСервере. Он срабатывает при открытии существующего объекта и при его перечитывании (например, после записи). Если же нужно ограничить доступ и в новом (еще не записанном) документе, используйте ПриСозданииНаСервере.
Разберем еще один нюанс: Кнопки командной панели. Кнопки «Провести», «Записать» и другие команды часто находятся в автоматических группах. Если вы блокируете Доступность всей командной панели, вы не сможете оставить доступной кнопку проведения. Всегда проверяйте, не является ли элемент, который вы пытаетесь оставить доступным, частью заблокированного «родителя».
Чтобы успешно решить задачу, пройдем по шагам:
ПриЧтенииНаСервере для размещения кода.ЭтаФорма.Элементы, в котором будем пропускать ГруппыФормы и элементы из списка Исключений.ТолькоПросмотр = Истина, для кнопок — Доступность = Ложь.Используя эти методы, мы добьемся стабильного поведения интерфейса, при котором пользователь сможет изменять только разрешенные данные и проводить документ, не имея доступа к основной финансовой или товарной части.